14
votes

I am looking at basic example of md-grid-list in Angular 2.

HTML Code :

<md-grid-list cols="4" rowHeight="100px">
   <md-grid-tile *ngFor="let tile of tiles"
         [colspan]="tile.cols"
         [rowspan]="tile.rows"
         [style.background]="tile.color">
         {{tile.text}}
    </md-grid-tile>
</md-grid-list>

TS Code :

export class GridListDynamicExample {
  tiles = [
    {text: 'One', cols: 3, rows: 1, color: 'lightblue'},
    {text: 'Two', cols: 1, rows: 2, color: 'lightgreen'},
    {text: 'Three', cols: 1, rows: 1, color: 'lightpink'},
    {text: 'Four', cols: 2, rows: 1, color: '#DDBDF1'},
  ];
}

The above code results in this : enter image description here How can I make the layout as "column" that is column "Two" to go below the rows(One and Four) on smaller screen size using some HTML directive or CSS?

Angular Material in Angular 1 had option to achieve by specifying "md-cols-xs="1" md-cols-sm="2" md-cols-md="4" md-cols-gt-md="6" ".

4
This is one of the drawbacks of using a framework that's still in beta. Responsive grid-lists haven't been implemented yet. - adamdport

4 Answers

11
votes

This is the simplest Way you can achive that :)

your.component.html

<md-card class="sub-category-grid" style="padding:0px;" (window:resize)="onResize($event)">

  <md-grid-list cols="{{test}}" rowHeight="1:1">
     <md-grid-tile *ngFor="let item of Items"> 
       {{item.title}}
    </md-grid-tile>
 </md-grid-list>

</md-card>

your.component.ts

// init this var with the default number of columns
test: any = 2;

Items: any = [
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" },
    {title: "title", img_src: "../../../assets/img/-samples/raketa.png", description: "Description" }
  ]


constructor() { }

ngOnInit() {

}


onResize(event) {
    const element = event.target.innerWidth;
    console.log(element);


    if (element < 950) {
      this.test = 2;
    }

    if (element > 950) {
      this.test = 3;
    }

    if (element < 750) {
      this.test = 1;
    }
  }
3
votes

You can add directive to your component and then do the work in directive like this;

import { Directive, ElementRef, Input, HostListener, Output } from '@angular/core';
import * as _ from  "lodash";
@Directive({ selector: '[myResponsive]' })

export class TestDirective {
  @Input() tiles;

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    if (event.target.innerWidth < 980) {
      _.each(this.tiles, tile => {
        tile.cols = 2;
        tile.rows = 1;
      });
    } else {
      this.tiles = [
        {text: 'One', cols: 3, rows: 1, color: 'lightblue'},
        {text: 'Two', cols: 1, rows: 2, color: 'lightgreen'},
        {text: 'Three', cols: 1, rows: 1, color: 'lightpink'},
        {text: 'Four', cols: 2, rows: 1, color: '#DDBDF1'}
      ];
    }
  }

  constructor(el: ElementRef) {

  }
}

You also need to add your directive to app.module.ts

import { TestDirective } from "./test.directive";
@NgModule({
  imports: [
      ...
  ],
  declarations: [
     TestDirective
  ]

And your HTML should be like this

<md-grid-list cols="4" rowHeight="100px">
   <md-grid-tile myResponsive [(tiles)]="tiles" *ngFor="let tile of tiles"
         [colspan]="tile.cols"
         [rowspan]="tile.rows"
         [style.background]="tile.color">
         {{tile.text}}
    </md-grid-tile>
</md-grid-list>

enter image description here

2
votes

As I understand the responsive part is currently located in flex-layout project. Some of the common utilities from this library will be moved to angular/cdk that material already uses. Flex-layout project provides an observable that you can subscribe to get notifications on break point changes - ObservableMedia. You can also use MediaService service (also from flex-layout) to assert the window sizes.

Therefore this code can be implements like that. Please notes that I use trackBy function to keep the original boxes when toggle happen.

    export class AppComponent  {
      tiles: Array<Object>;
      public columns = 4;
      private subscription: Subscription;

      tilesBig = [
        {text: 'One', cols: 3, rows: 1, color: 'lightblue', id: 1},
        {text: 'Two', cols: 1, rows: 2, color: 'lightgreen', id: 2},
        {text: 'Three', cols: 1, rows: 1, color: 'lightpink', id: 3},
        {text: 'Four', cols: 2, rows: 1, color: '#DDBDF1', id: 4},
      ];

      tilesSm = [
        {text: 'One', cols: 3, rows: 1, color: 'lightblue', id: 1},
        {text: 'Three', cols: 1, rows: 1, color: 'lightpink', id: 3},
        {text: 'Four', cols: 2, rows: 1, color: '#DDBDF1', id: 4},
        {text: 'Two', cols: 3, rows: 1, color: 'lightgreen', id: 2},
      ];

      constructor(private _media$: ObservableMedia,
                  private mediaService: MediaService) {
        this.subscription = this._media$.subscribe((e: MediaChange) => {
          this.toggle();
        });
      }

      ngOnInit() {
        this.toggle();
      }

      private toggle() {
        const isSmall = this.mediaService.isActive('lt-md');
        this.columns = isSmall ? 3 : 4;
        this.tiles = isSmall ? this.tilesSm : this.tilesBig;
      }

      trackById(index: number, item: any): string { return item['id']; }
    }

You can look at code https://stackblitz.com/edit/angular-t325tj?embed=1&file=app/app.component.ts

0
votes

Making responsive design in angular 4 is not as simple as it is in bootstrape. To make md-grid-list responsive or should change view according to device width then we need to use flex layout library

To have clearity about how reponsive things work in angular visit below links

visit http://brianflove.com/2017/05/03/responsive-angular/
demo http://run.plnkr.co/preview/cja10xr7900083b5wx6srd0r6/