angularangular-materialmat-tabangular16mat-sidenav

Sidenav in dynamic tabs (Angular Material) is only working for the first tab


For my web application I dynamically create tabs with *ngFor and each tab includes a sidenav-container with the sidenav and content. For each tab it should be possible to show and toggle the sidebar.

I have these components:

I also do have a service to handle toggling the sidebar.

app.component.html

<mat-tab-group class="content-container" mat-align-tabs="center"> 
  <mat-tab *ngFor="let tab of tabs" [label]="tab.name" >
     
        <mat-sidenav-container>
              <mat-sidenav #sidenav position="start" mode="side">  
                    <app-header></app-header>
                    <app-sidenav></app-sidenav>
              </mat-sidenav>
              
              <mat-sidenav-content >
                    <app-content></app-content>
              </mat-sidenav-content>
        </mat-sidenav-container>
        
  </mat-tab>

app.component.ts

...
@ViewChild('sidenav', { static: false }) sidenav: MatSidenav

ngOnInit() {
    this.sidenavService.sidenavToggleSubject.subscribe(()=> {
        this.sidenav.toggle()
    })
}
...

header.html

<mat-toolbar color="primary">
   <button mat-icon-button class="toolbar-menu-icon" (click)="toggleSidenav()">
     <mat-icon class="toolbar-menu-icon">menu</mat-icon>
   </button>
</mat-toolbar>

header.ts

public toggleSidenav(){
    this.sidenav.toggle()
  }

sidenav.service.ts

...
public sidenavToggleSubject: BehaviorSubject<any> = new BehaviorSubject(null)

  public toggle() {
    return this.sidenavToggleSubject.next(null)
  }
...

Problem: The sidebar does only exist for the FIRST tab. Having the first tab activated, toggling the sidebar just works as expected. But when I change to another tab and I toggle the sidebar, the sidebar of the first tab is toggled.

Example: When the sidebar of Tab1 is opened and I change to Tab 2 which does not show a sidebar and I click the icon to toggle the sidebar, the sidebar of Tab1 is closed, instead of opening a sidebar for Tab2.

For me it seems as there would be only one instance of the sidebar (which is ok, because I later want to dynamically set the content of the sidebar depending on the chosen tab), but why is it only shown on the first tab?


Solution

  • You are generating your tabs via an *ngFor, so all your sidenav are generated. Angular material only "shows" one or the other, but they all exist. So your @ViewChild in your component only gets the first #sidenav it sees.

    So what you would have to do is an @ViewChildren to get the list of #sidenav, so when you receive a toggle event, you check which tab is active, and toggle the this.sidenav[activeTabIndex] instead.

    @ViewChildren('sidenav', { static: false }) sidenavs: QueryList<MatSidenav>;
    activeTabIndex: number = 0;
    
    ngOnInit() {
        this.sidenavService.sidenavToggleSubject.subscribe(()=> {
            this.sidenavs.get(activeTabIndex).toggle();
        })
    }
    
    onTabChange(newIndex: number) {
      this.activeTabIndex = newIndex;
    }