7

I'm trying to create a nested mat-menu items for my angular app. I got some solutions only where the nested options would appear as a pop-up, where i'm expecting it to be a drop-down where we could choose the menu lying under it when triggered.

I tried using the mat-sidenav-container and gave a few conditions to open the menu based on the condition

 <mat-nav-list>
     <mat-list-item (click)="showSubmenu = !showSubmenu" class="parent">
          <span class="full-width" *ngIf="isExpanded || 
            isShowing">Users</span>
       <mat-icon mat-list-icon>supervisor_account</mat-icon>
        <mat-icon class="menu-button" [ngClass]="{'rotated' : 
          showSubmenu}" *ngIf="isExpanded || 
             isShowing">expand_more</maticon>
        </mat-list-item>
        <div class="submenu" [ngClass]="{'expanded' : showSubmenu}" 
           *ngIf="isShowing || isExpanded">
          <div [routerLink]="['users']" routerLinkActive="active" 
             (click)="toggleSide()">Add Users</div>
          </div>
    </mat-nav-list>
``in the above code. i would like to nest Manage Users under Users list item``` and my .ts file follows:

showSubmenu: boolean = false;
  isShowing = false;
  showSubSubMenu: boolean = false;
  isExpanded = true;

i would like the expected result to be like this (https://stackblitz.com/edit/material-sidenav-example?file=app%2Fsidenav-autosize-example.html)

I did try using the same element as in the above link, but i couldn't get it working. i might be doing a very silly mistake. Thanks in advance !!

krishna ram
  • 85
  • 1
  • 2
  • 11

5 Answers5

8

You can implement a generic menu list item, Here is an example:

https://dynamic-nested-sidenav-menu.stackblitz.io

  • 1
    Thanks for the effort @mohammed. Can i please get the source of it and where in my code can i edit to make it happen like the example you mentioned? – krishna ram May 09 '19 at 08:25
  • 3
    The example I mentioned creates a dynamic generic menu list item which can be re-used when wanted. Exactly this component: https://stackblitz.com/edit/dynamic-nested-sidenav-menu?file=app%2Fmenu-list-item%2Fmenu-list-item.component.ts – Mohamed Ben Amar May 09 '19 at 08:35
  • Just a moment, I ll give an the solution for a single item – Mohamed Ben Amar May 09 '19 at 08:43
  • Glad i helped, ok no problem – Mohamed Ben Amar May 09 '19 at 11:58
  • 1
    Good that you gave the link for editing your stackblitz item. Was not able to get the source from the link you are giving in your answer – Torsten Barthel Sep 15 '20 at 14:06
  • Btw, I like navService approach. One suggestion...you could just call toggle() method on hamburger menu. That will open and close the sidenav and you do not need to handle them separately. – hbthanki Mar 18 '21 at 01:29
1

From your code

     <mat-nav-list style="width:300px">
        <mat-list-item (click)="showSubmenu = !showSubmenu" class="parent">
            <span class="full-width" *ngIf="isExpanded || 
                isShowing">Users</span>
            <mat-icon mat-list-icon>supervisor_account</mat-icon>
            <mat-icon class="menu-button" [ngClass]="{'rotated' : 
              showSubmenu}" *ngIf="isExpanded || 
                 isShowing">expand_more</mat-icon>
            </mat-list-item>
        <div *ngIf="showSubmenu">
        <a menu-list-item >
          Mangage users
        </a>
        </div>
            <div class="submenu" [ngClass]="{'expanded' : showSubmenu}" 

               *ngIf="isShowing || isExpanded">
              <div  
                 (click)="toggleSide()">Add Users</div>
              </div>
        </mat-nav-list>

But this is not good in Practice and if you have a lot of nesting, in that case use a generic one.

  • can you get me a working example in https://stackblitz.com/ please? i think it is missing the service and router property – krishna ram May 09 '19 at 09:39
  • 1
    https://stackblitz.com/edit/material-sidenav-example?file=app%2Fsidenav-autosize-example.html – Mohamed Ben Amar May 09 '19 at 10:05
  • i used the above and considered that as an example with which i tried implementing the same in my code. it did not work. i have updated the question again to be more specific. Thanks for the time @Mohammed – krishna ram May 09 '19 at 10:12
  • it's almost there and i exactly fixed it with your help. thanks @mohamed – krishna ram May 09 '19 at 11:37
  • when i tried adding nested menus to multiple menus. I clicked the drop down for one and everything opens up. is there a fix for this ? @mohamed – krishna ram May 10 '19 at 06:00
  • it's because you are using the same bool variable "showSubmenu" for all menus. I recommend you to use a generic one and control your submenus data from the ts – Mohamed Ben Amar May 10 '19 at 12:04
  • No. i tried using a different variable name showSubmenuu for the second menu. it still did not work – krishna ram May 11 '19 at 05:32
1

Unrelated to the OP's specific needs, but here's a fun nested menu I just made:

It demonstrates how Angular templates work similar to Javascript in that templates create a sort of closure scope. Because of that I was able to create a dynamic nested menu with no duplicated code.

The key here is the method call setFont(target, font) where the value of target is 'closed' over so when the item is clicked it refers to the correct one.

<!-- fonts menu -->
<mat-menu #fontMenu="matMenu">

    <ng-container *ngFor="let target of ['Header', 'Body']">
        
        <!-- submenu for each target -->
        <button mat-menu-item [matMenuTriggerFor]="fontsMenu">
            <span>{{ target }} font</span>
        </button>

        <!-- submenu for each font -->
        <mat-menu #fontsMenu="matMenu">
            <ng-container *ngFor="let font of ['Arial', 'Comic Sans']">

                <button mat-menu-item (click)="setFont(target, font)">
                    <span>{{ font }}</span>
                </button>  

            </ng-container>
        </mat-menu>

    </ng-container>

</mat-menu>

enter image description here

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0

According to Angular material

     <button mat-button [matMenuTriggerFor]="animals">Animal index</button>

<mat-menu #animals="matMenu">
  <button mat-menu-item [matMenuTriggerFor]="vertebrates">Vertebrates</button>
  <button mat-menu-item [matMenuTriggerFor]="invertebrates">Invertebrates</button>
</mat-menu>

<mat-menu #vertebrates="matMenu">
  <button mat-menu-item [matMenuTriggerFor]="fish">Fishes</button>
  <button mat-menu-item [matMenuTriggerFor]="amphibians">Amphibians</button>
  <button mat-menu-item [matMenuTriggerFor]="reptiles">Reptiles</button>
  <button mat-menu-item>Birds</button>
  <button mat-menu-item>Mammals</button>
</mat-menu>

<mat-menu #invertebrates="matMenu">
  <button mat-menu-item>Insects</button>
  <button mat-menu-item>Molluscs</button>
  <button mat-menu-item>Crustaceans</button>
  <button mat-menu-item>Corals</button>
  <button mat-menu-item>Arachnids</button>
  <button mat-menu-item>Velvet worms</button>
  <button mat-menu-item>Horseshoe crabs</button>
</mat-menu>

<mat-menu #fish="matMenu">
  <button mat-menu-item>Baikal oilfish</button>
  <button mat-menu-item>Bala shark</button>
  <button mat-menu-item>Ballan wrasse</button>
  <button mat-menu-item>Bamboo shark</button>
  <button mat-menu-item>Banded killifish</button>
</mat-menu>

<mat-menu #amphibians="matMenu">
  <button mat-menu-item>Sonoran desert toad</button>
  <button mat-menu-item>Western toad</button>
  <button mat-menu-item>Arroyo toad</button>
  <button mat-menu-item>Yosemite toad</button>
</mat-menu>

<mat-menu #reptiles="matMenu">
  <button mat-menu-item>Banded Day Gecko</button>
  <button mat-menu-item>Banded Gila Monster</button>
  <button mat-menu-item>Black Tree Monitor</button>
  <button mat-menu-item>Blue Spiny Lizard</button>
  <button mat-menu-item disabled>Velociraptor</button>
</mat-menu>
Mustafa Omran
  • 354
  • 5
  • 7
  • Thanks for the effort @mustafa, but this isn't what i expected. i wanted the sumenu to be animated exactly like this (https://stackblitz.com/edit/material-sidenav-example?file=app%2Fsidenav-autosize-example.html). i dont wanted them to be animated as a pop-up as the page becomes messier with this. – krishna ram May 09 '19 at 08:23
0

I did it like this

<mat-nav-list>
  <mat-accordion>
    <mat-expansion-panel style="box-shadow: none">
      <mat-expansion-panel-header style="margin-left: -8px">
        <mat-panel-title> <mat-icon>code</mat-icon>&nbsp;Developers </mat-panel-title>
      </mat-expansion-panel-header>
      <a
        mat-list-item
        routerLink="test"
        class="sidenav__list-item list-sub-item"
        [routerLinkActive]="['active']"
        (click)="handleClickEvent($event)"
      >
        <mat-icon>api</mat-icon>
        <span style="padding-top: 11px;">Api Keys</span>
      </a>
      <a
        mat-list-item
        routerLink="test1"
        class="sidenav__list-item list-sub-item"
        [routerLinkActive]="['active']"
        (click)="handleClickEvent($event)"
      >
        <mat-icon>webhook</mat-icon>
        <span style="padding-top: 11px;">Web Hooks</span>
      </a>
    </mat-expansion-panel>
  </mat-accordion>
</mat-nav-list>

this is how it looks finally

Tyler2P
  • 2,324
  • 26
  • 22
  • 31