Reputation: 53
I'm building an Angular 7 site with Angular Material (I'm kind of new in web dev). I'm stuck with something that seems ridiculously trivial: in my products.component I want to use the Angular Material Button Toggle to switch between a grid view (default) and a list view of my products. A feature we see on so many ecommerce. Here is my simplified code:
<mat-button-toggle-group value="grid">
<mat-button-toggle value="grid">
<mat-icon>view_module</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="list">
<mat-icon>view_list</mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
The grid view of the products (has to be the default view):
<div *ngFor="let product of products">
<a>
...
</a>
</div>
The list view of the products:
<div>
<ul>
<li *ngFor="let product of products"></li>
</ul>
</div>
I've tried with ViewChild, NgModel, NgSwitch, TemplateRef, all kind of solutions... I'm missing something and I have spend a considerable time on this so I'm relying on you! Thanks in advance
Edit: without routing implemented my app.component looks like this:
<app-header>
<app-products>
<app-footer>
My products.component is built like this (simplified)
<mat-toolbar>
<mat-button-group>
...
</mat-button-group>
</mat-toolbar>
<div class="container">
<div *ngFor="let product of products">
<a>
...
</a>
</div>
<div>
<ul>
<li *ngFor="let product of products">
...
</li>
</ul>
</div>
</div>
So all in one component. Create two child components for the grid view and the list isn't the way to go, right ? I've tried anyway by moving the code inside the div.container in another component where I've experiment with this:
@Component({
templateUrl:
`
<div #listTemplate>
<p>List View</p>
</div>
<div #gridTemplate>
<p>Grid View</p>
</div>
`
})
export class ... {
@ViewChild('listTemplate') listTemplate: TemplateRef<any>;
@ViewChild('gridTemplate') gridTemplate: TemplateRef<any>;
}
But I've failed to bind this with the click on the button toggle. The Material Button Toggle emits a change event on click so it should let me use ngModel. I've tried something like this:
<mat-toolbar>
<mat-button-group>
<mat-button-toggle (click)="change(view.value)">...</mat-button-toggle>
<mat-button-toggle (click)="change(view.value)">...</mat-button-toggle>
</mat-button-group>
</mat-toolbar>
<div class="container">
<div *ngFor="let product of products" [(ngModel)]="grid" #view>
<a>
...
</a>
</div>
<div [(ngModel)]="list" #view>
<ul>
<li *ngFor="let product of products">
...
</li>
</ul>
</div>
</div>
But don't know how insert the appropriate template with change(value). ngTemplateOutlet could be an appropriate solution but I haven't tried it. Obviously I'm lacking some understanding of this Angular features but I've succeeded in implemeting other things in my site, so I want to achieve this one.
Upvotes: 3
Views: 9841
Reputation: 5017
Here is a working sample of the Toggle button on StackBlitz.
<mat-button-toggle-group [value]="toggle" (change)="toggleView($event)">
<mat-button-toggle [value]="true">
Grid
</mat-button-toggle>
<mat-button-toggle [value]="false">
List
</mat-button-toggle>
</mat-button-toggle-group>
<span>Current Value: {{toggle}}</span>
<div *ngIf="toggle">Grid</div>
<div *ngIf="!toggle">List</div>
TypeScript:
import { Component} from '@angular/core';
import {MatButtonToggleChange} from '@angular/material';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent{
toggle: boolean = true;
constructor(){
}
toggleView(change: MatButtonToggleChange){
this.toggle = change.value;
}
}
Upvotes: 3