9

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 !!

5 Answers 5

12

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

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

Here is a link to the source: https://stackblitz.com/edit/dynamic-nested-sidenav-menu?file=app%2Fmenu-list-item%2Fmenu-list-item.component.ts

Sign up to request clarification or add additional context in comments.

6 Comments

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?
The example I mentioned creates a dynamic generic menu list item which can be re-used when wanted. Exactly this component: stackblitz.com/edit/…
Just a moment, I ll give an the solution for a single item
Glad i helped, ok no problem
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
|
4

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

1 Comment

this is better than the custom approach from above
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.

7 Comments

can you get me a working example in stackblitz.com please? i think it is missing the service and router property
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
it's almost there and i exactly fixed it with your help. thanks @mohamed
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
|
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>

1 Comment

Thanks for the effort @mustafa, but this isn't what i expected. i wanted the sumenu to be animated exactly like this (stackblitz.com/edit/…). i dont wanted them to be animated as a pop-up as the page becomes messier with this.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.