How to create a responsive (varying column count) Angular-Material card grid
Asked Answered
R

4

18

I'm trying to create a grid of Angular-Material cards that behaves somewhat like a Bootstrap grid. Ideally, cards will be full-width for small screen widths and jump to two columns at larger breakpoints.

Demo with 2 cards

The problem is that A-M creates columns for each card. I haven't figured out how to specify the number of columns for each breakpoint.

Demo with 5 cards

Here's the basis of the markup I'm using, which takes the card layout from rows to columns at the first breakpoint:

<div ng-app layout="column" layout-gt-sm="row" class="layout-sm-column layout-row">
  <div flex class="flex" ng-repeat="i in [1,2,3,4,5] track by $index">
    <md-card>

There's a similar question on SO already, but accepted answer is unsatisfactory as it uses custom CSS and the cards aren't fluid-width. I've found no other similar examples.

I suppose I could loop every two cards with Angular and create stacked sets, but that seems needlessly cumbersome. I have to think that Material provides for a better solution. Also, such solutions would leave whitespace in the page where cards vary in height. Material seems geared toward a Masonry-like flex layout, and I'd like to stick with that.

Thanks.

Roxi answered 14/12, 2015 at 20:12 Comment(4)
Possible with just css, even with a masonry look/style. designshack.net/articles/css/masonry/#bsap_1610Faradmeter
The question is how to do it with Angular Material. I have a lot of experience with other libraries and techniques. This seems to be a deficiency of A.M., however, unless I'm missing something.Roxi
I've run into this exact same issue and there isn't a native solution that is going to do a masonry type grid for you. AM's responsiveness comes from the flexbox containers, not at the directive-level so they don't really communicate with each other. I actually created stacked sets just as you suggested yourself.Chambray
using css3 you can define columns:3 on your md-card, media query width columns:2 and finally mobile: columns:1 for exampleOrian
L
18

You can use the material Grid-List, it allows for custom col-spans and animates the changes when the width changes.

I adapted the sample from the site and added md-card in the contents. Make sure to add layout-fill on the md-card. You can easily adapt the sample for your column count.

http://codepen.io/anon/pen/QypjWY

I also adapted your 5 card sample. You need to know the height of the cards in order to use the Grid-List, but you can easily achieve the 100% height on small screens. You can use ratios or fixed CSS heights for the rows and then it is your cards job to display the content in a flexible way.

<md-grid-list ng-app="app" layout-fill flex
    md-cols-sm="1"
    md-cols-md="2"
    md-cols-gt-md="5"
    md-row-height-sm="100%"
    md-row-height="600px"
    md-gutter="8px">
    <md-grid-tile ng-repeat="i in [1,2,3,4,5] track by $index">
        <md-card layout-fill>

http://jsfiddle.net/2afaok1n/34/

Edit:

If you are instead looking for some kind of staggered grid, then you have to add a library: angular-deckgrid, it just provides the grid layout, everything in the content is angular-material. Unlike angular-masonry this library doesn't have any dependencies. If you are not worried about adding jQuery and the like then you can also use angular-masonry.

<div ng-app="app" ng-controller="DeckController" flex layout="column">
   <deckgrid class="deckgrid" flex source="data">
       <md-card>

The important part for the deck layout is the CSS configuration. With this you configure the number of columns and their width. I have used a media query for the angular-material sm breakpoint to switch to single column layout.

.deckgrid::before {
  content: '4 .column.column-1-4';
  font-size: 0;
  visibility: hidden;
}

.deckgrid .column {
  float: left;
}

.deckgrid .column-1-4 {
  width: 25%;
}

.deckgrid .column-1-1 {
  width: 100%;
}

@media screen and (max-width: 960px) {
  .deckgrid::before {
    content: '1 .column.column-1-1';
  }
}

http://jsfiddle.net/2afaok1n/39/

Edit 2:

There is also a masonry version which doesn't require jQuery and a simple directive to use it: angular-masonry-directive. Here is an example, it works similar to the other one.

http://jsfiddle.net/xjnp97ye/1/

Lapwing answered 5/1, 2016 at 11:21 Comment(3)
The first example seems like a good start, but I'm not sure I can live with the fixed heights. I've simplified the demo for my purposes: codepen.io/anon/pen/YwZwbz The second one leaves varying whitespace between rows, as I mentioned in my question. It probably won't work.Roxi
I'm intrigued by your update, but the third example (39) doesn't seem to exhibit responsive behavior. The fourth example looks like a good option.Roxi
You are right, the 3rd one is somewhat limited. If you run that example with a big width and then reduce the width, it will act responsive but not the other way around. It will however work as expected on different devices with a fixed width and/or redraw, e.g. device rotation etc. The library parses the pseudo ::before CSS block and must get something wrong there.Lapwing
J
2

if i understood your question right Then use this code and replace the hello with anything you like

<md-grid-list md-cols-lg="12" md-cols-gt-lg="15" md-cols-xs="3" md-cols-sm="6" md-cols-md="9" md-row-height-gt-md="1:1" md-row-height-md="1:1" md-row-height="1:2" md-gutter-gt-md="16px" md-gutter-md="8px" md-gutter="4px">
            <md-grid-tile ng-repeat="contact in contacts" md-colspan="3" md-rowspan-gt-sm="4" style="background:red;">
                hello
            </md-grid-tile>
        </md-grid-list>
Julesjuley answered 25/2, 2016 at 14:15 Comment(3)
This is a great answer. The only problem is the grid list has some incompatibilities, like, for instance, with the infinite scrollOnomatology
@Onomatology i agree , but can't the grid list be kept inside a virtual-repeat ? there we can implement infinite scroll ..Julesjuley
I think I tried that, and had this problem- github.com/angular/material/issues/5312Onomatology
M
1

If I understood the question right, this works like a charm:

<body ng-app="app" ng-cloak>
  <div layout="column" layout-gt-sm="row" layout-wrap>
  <div flex="25" flex-gt-sm="50" ng-repeat="i in [1,2, 3, 4, 5] track by $index">
    <md-card>
     <!--  You code-->
    </md-card>
  </div>
  </div>
</body>

Plunker with multiple breakpoints : (resize the inner window, not the browser window) http://plnkr.co/edit/8QPYdzLD8qzEbdz5sesE?p=preview

The plunker has been updated to show cards with different height.
2 directives have been made, so the biggest height of all cards is kept in memory and this one is applied to all cards.

Malefaction answered 9/1, 2016 at 22:24 Comment(6)
Thanks, but I can't get it to show more than one breakpoint change. Can you improve the demo to show at least 3?Roxi
I've forked a version with varying content. As you can see, it doesn't do well. The cards run together and cut off the content. Thoughts? plnkr.co/edit/VNyWOpCocKGfY0qX2IjK?p=previewRoxi
I started making an improved plnk with directives, but it makes no sense : plnkr.co/edit/8QPYdzLD8qzEbdz5sesE?p=preview . Finally you have this silly option 2 plnkr.co/edit/ieafIYh6zVqI7ema3Mnz?p=preview and my answear is that angular material has it limits. I would make 3 versions with ng-show/ng-hide each block on window sizeMalefaction
Thanks for the effort. It is a frustrating situation.Roxi
See updated Plunker. Directives are working. Still need to handle the height of the card (on bigger screens, 2nd column is going on 1st. I think it's pretty easy)Malefaction
You need to resize and "stop" and "run" in fact... :/Malefaction
D
1
<div  ng-repeat="i in [1,2, 3, 4, 5] track by $index" flex-xs="100" flex-sm="50" flex-md="50" flex="33">
<md-card>

  <md-card-title >
    <md-card-title-text >
      <span class="md-headline">Demo Title {{i}}</span>
      <span class="md-subhead">Demo Description</span>
    </md-card-title-text>    
  </md-card-title>
</md-card>
</div>

Check this example: http://codepen.io/ktn/pen/jqNBOe

Dreadful answered 25/2, 2016 at 10:19 Comment(1)
right, but what if your cards aren't all the same heightOnomatology

© 2022 - 2024 — McMap. All rights reserved.