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?
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;
}