I am looking for support within Angular Material2 for nested menus within a sidebar. The top level would typically be closed by default, and opening a top level would expose nested menu items.
I thought this made sense as a starting point, but the child nav items render (poorly) outside of the parent items:
plnkr
<md-sidenav-container class="my-container">
<md-sidenav #sidenav class="my-sidenav">
<md-list>
<md-list-item>
<h3 md-line> First Parent </h3>
<md-nav-list>
<a md-list-item href="#">First Child</a>
<a md-list-item href="#">Second Child</a>
<a md-list-item href="#">Third Child</a>
</md-nav-list>
</md-list-item>
<md-list-item>
<h3 md-line> Second Parent </h3>
<md-nav-list>
<a md-list-item href="#">First Child</a>
<a md-list-item href="#">Second Child</a>
</md-nav-list>
</md-list-item>
</md-list>
</md-sidenav>
<div class="my-container">
<button md-button (click)="sidenav.open()">Open</button>
</div>
</md-sidenav-container>
Has anyone created this kind of sidebar menu with @angular/material?
I know this is an old question, but for others coming upon this page looking for the same thing, as I did, here's how I took care of it with the current version of Angular Material (6.4.6) and once you get the CSS styles done right, it works beautifully.
Please note that there still is no official support for this functionality, and you have to set it up yourself, which could be done a number of ways, but I chose to use only Angular Material components.
Here's example markup with some comments, using an object for your nav links:
<mat-sidenav-container>
<mat-sidenav #sidenav
class="sidenav"
[mode]="mobileQuery.matches ? 'over' : 'side'"
[opened]="mobileQuery.matches ? false : true">
<mat-nav-list>
<!-- wrap all the nav items in an accordion panel -->
<mat-accordion [displayMode]="flat">
<div *ngFor="let navItem of navList">
<!-- use a simple div for an item that has no children,
match up the styling to the expansion panel styles -->
<div class="nav-head" *ngIf="navItem.pages.length === 0">
<a class="nav-link"
[routerLink]="navItem.link"
routerLinkActive="selected"
(click)="closeSidenav()">
<mat-icon>{{navItem.icon}}</mat-icon>
<span class="nav-link-text">{{navItem.heading}}</span>
</a>
</div>
<!-- use expansion panel for heading item with sub page links -->
<mat-expansion-panel *ngIf="navItem.pages.length > 0"
class="mat-elevation-z0">
<mat-expansion-panel-header class="nav-head" [expandedHeight]="'48px'">
<mat-panel-title class="nav-link">
<mat-icon>{{navItem.icon}}</mat-icon>
<span class="nav-link-text">{{navItem.heading}}</span>
</mat-panel-title>
</mat-expansion-panel-header>
<div class="nav-section">
<!-- loop through all your sub pages inside the expansion panel content -->
<div *ngFor="let navPage of navItem.pages"
class="nav-item">
<a class="nav-link"
[routerLink]="navPage.link"
routerLinkActive="selected"
(click)="closeSidenav()">{{navPage.title}}</a>
</div>
</div>
</mat-expansion-panel>
</div>
</mat-accordion>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<div class="container-fluid">
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
EDIT: To answer a couple of additional questions that were made, mobileQuery is coming from the Angular Material CDK which adds some helpers for detecting mobile breakpoints inside your components. See here: Angular Material CDK Layout
Also, my component file really doesn't do anything in this case other than pull the correct nav object to be displayed from a service, but here is an example of how I set up the objects (of course they could be whatever you need them to be)
[
{
heading: 'Dashboard',
icon: 'dashboard',
link: '/dashboard',
pages: []
},
{
heading: 'Main Heading',
icon: 'settings',
link: '/settings',
pages: [
{
title: 'Subpage',
link: '/settings/advanced',
icon: ''
}
]
}
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With