Angular Material: using mat-sidenav, cannot read property 'toggle' of undefined

Viewed 7829

I have an Angular 8 project with Angular Material 8 that cannot toggle the sidenav via a button in the same component. The javascript console says that

cannot read property 'toggle' of undefined

but the sidenav has the reference variable in the template.

I have made sure the button is in the template so that I don't have to worry about event emitters or other trickery. This should be straightforward.

HTML

<mat-toolbar color="primary">
  <button mat-icon-button (click)="sidenav.toggle()" *ngIf="(isHandset$ | async)"><mat-icon>menu</mat-icon></button>
  <span>This Be Me App, Matey</span>
</mat-toolbar>
<mat-sidenav-container class="sidenav-container">
  <mat-sidenav #sidenav class="sidenav" fixedInViewport="true" *ngIf="isAuthenticated()"
      [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
      [mode]="(isHandset$ | async) ? 'over' : 'side'"
      [opened]="(isHandset$ | async) ? 'false' : 'true'">
    <mat-toolbar><mat-icon (click)="sidenav.toggle()" *ngIf="(isHandset$ | async)">arrow_back</mat-icon> Menu</mat-toolbar>
    <mat-nav-list>
      <a mat-list-item [routerLink]="['/home']" routerLinkActive="active">Home</a>
      <a mat-list-item (click)="logout()">Logout</a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content class="content">    
    <!-- Add Content Here -->
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>

The menu button appears and disappears at the breakpoint like expected, but clicking it gives the error.

What should happen is that the button only appears when you get below the isHandset$ break (which happens) and then it should open over the top of the content (which doesn't happen). Since the #sidenav reference variable is in the mat-sidenav tag it seems like I've got it set up properly.

1 Answers

the error you shared must have a dependency or something missing; to see the working behavior, we had to address the 2 *ngIf conditions in your code:

  • isAuthenticated() -- which could be false, we don't know the logic you had used
  • (isHandset$ | async) -- we don't know the observable logic

assuming these 2 *ngIf conditions to be true, the code works fine... no error of 'cannot read property 'toggle' of undefined'

relevant ts:

import {Component} from '@angular/core';

@Component({
  selector: 'sidenav-open-close-example',
  templateUrl: 'sidenav-open-close-example.html',
  styleUrls: ['sidenav-open-close-example.css'],
})
export class SidenavOpenCloseExample {
  events: string[] = [];
  opened: boolean;
  isHandset$:boolean =true;
  isAuthenticated(){ return true;}

  shouldRun = [/(^|\.)plnkr\.co$/, /(^|\.)stackblitz\.io$/].some(h => h.test(window.location.host));
}

you can check working stackblitz here

Related