3

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.

3
  • Can you add your experiments to your question? As it is, there is no connection between the different displays and the button toggle group. Commented Nov 2, 2018 at 21:33
  • Can you show a bit more of how you structured everything? how are the components built? is it a single component? what are you using to store the value you get from the toggle? Commented Nov 2, 2018 at 21:38
  • I've edited my post Commented Nov 2, 2018 at 23:03

1 Answer 1

3

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;
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Oh my, it works! So simple yet I've failed to find it by myself.Thank you for your time!
If you use two way binding you can remove the change event completely. So do this: [(value)]="toggle"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.