Dynamic nested Material menu from json object in Angular 5 Dynamic nested Material menu from json object in Angular 5 angular angular

Dynamic nested Material menu from json object in Angular 5


The following structure should work for you:

<button mat-button [matMenuTriggerFor]="main_menu">My menu</button><mat-menu #main_menu="matMenu">  <ng-container *ngFor="let mainItem of objectKeys(my_menu)">    <button mat-menu-item [matMenuTriggerFor]="sub_menu">{{ mainItem }}</button>    <mat-menu #sub_menu="matMenu">       <button *ngFor="let subItem of my_menu[mainItem]" mat-menu-item>{{ subItem }}</button>    </mat-menu>  </ng-container></mat-menu>

Since I placed sub_menu inside the embedded template (*ngFor) we can use the same name for template reference variable(#sub_menu).

Stackblitz Example


Here is a StackBlitz example of an arbitrarily deep nesting based on JSON (authored by @Splaktar)

The key to arbitrary nesting is the self-referencing menu-item.component:

import {Component, Input, OnInit, ViewChild} from '@angular/core';import {Router} from '@angular/router';import {NavItem} from '../nav-item';@Component({  selector: 'app-menu-item',  templateUrl: './menu-item.component.html',  styleUrls: ['./menu-item.component.scss']})export class MenuItemComponent implements OnInit {  @Input() items: NavItem[];  @ViewChild('childMenu') public childMenu;  constructor(public router: Router) {  }  ngOnInit() {  }}
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">  <span *ngFor="let child of items">    <!-- Handle branch node menu items -->    <span *ngIf="child.children && child.children.length > 0">      <button mat-menu-item color="primary" [matMenuTriggerFor]="menu.childMenu">        <mat-icon>{{child.iconName}}</mat-icon>        <span>{{child.displayName}}</span>      </button>      <app-menu-item #menu [items]="child.children"></app-menu-item>    </span>    <!-- Handle leaf node menu items -->    <span *ngIf="!child.children || child.children.length === 0">      <button mat-menu-item [routerLink]="child.route">        <mat-icon>{{child.iconName}}</mat-icon>        <span>{{child.displayName}}</span>      </button>    </span>  </span></mat-menu>