'Angular 2 change sidenav content depending on the current router state
I am developing single page application in Angular 2. I am using angular material mat-sidenav and mat-toolbar. Toolbar has sidenav toggle button, buttons to open 'Clients' section and 'Reports' section. This structure is common throughout the project.
I have to change the content in the sidenav (and in the main field) depending on the current state of the router. So, if the 'Clients' section is opened the sidenav should show some subsections related to the clients. Similarly, for 'Reports' section only subsections related to the reports should be available. How do I do it?
Solution 1:[1]
I have figured out how to do this with the layout approach. You can see the example of implementation of the admin system using this approach here
Solution 2:[2]
I've done that by checking if URL path contains some specified part. For example if you want to have visible submenu for clients it could be '/clients'
etc. Then you just use *ngIf
directive:
<ul *ngIf="location.includes('/clients')">
To check current URL you have to listen for router changes. So, in the component where you have sidenav content you need to subscribe to router.events
property.
import { Router, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';
...
export class SidenavComponent {
location = '';
constructor(router: Router) {
router.events
.filter(event => event instanceof NavigationEnd)
.subscribe((event: NavigationEnd) => {
this.location = event.url
})
...
Apart of NavigationEnd
router emit multiple other events so we filtering them in example above and after subscription, we're updating location
property
Solution 3:[3]
Another alternative is to use the [hidden]
property. I started out using *ngIf
but that recreates the component, which in my case retriggered some filtering that caused the main content to redraw. [hidden]
allows me to selectively display content without component destruction. Usage like this:
<mat-sidenav-container class="sidenav-container">
<mat-sidenav>
<div >
<div [hidden]="activeContent !== 'sidenav1'">
<p>SIDENAV 1</p>
</div>
<div [hidden]="activeContent !== 'sidenav2'">
<p>SIDENAV 2</p>
</div>
</div>
</mat-sidenav>
<mat-sidenav-content>
<p>MAIN CONTENT<p>
</mat-sidenav-content>
</mat-sidenav-container>
Notes:
activeContent
is a public field on the component class containing the sidenav name (or more specifically, a string literal union type for design-time type checking)- If you're using
side
mode for the sidenav and you have inconsistent widths across your sidenav content, you may observe that the main content does not resize to fill the available space. The best solution I came up with for this is to triggerthis._sidenav.close().then(_ => this._sidenav.open());
in the component class when the sidenav content changes.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nikita Marinosyan |
Solution 2 | Lothir |
Solution 3 | tek |