Home > Enterprise >  Angular MatMenu not working in double ngFor loop
Angular MatMenu not working in double ngFor loop

Time:01-03

Using Angular 13, I have been trying to add a menu using Angular MatMenu (https://material.angular.io/components/menu/overview) which is conditionally shown. Basically a bar shows button (operations) and some may have suboperations. In this case I want to display the suboperations when clicking on the button.

Here is the basic code I have, which is the complete html since there is another menu in the beginning. Note that removing it does not change the behavior.

<div  *ngIf="!!selectedCategory">
  <div  *ngIf="rateOrDislocationEnabled; else simpleAggregation">
    <button color="primary" mat-button mat-icon-button [matMenuTriggerFor]="categoryMenu" >
      <div >{{ selectedCategory | agReplace: "_":" " }}</div>
      <mat-icon >arrow_drop_down</mat-icon>
    </button>
    <mat-menu #categoryMenu="matMenu" [overlapTrigger]="true" data-testid="categories-menu">
      <button mat-menu-item *ngFor="let category of availableCategories" (click)="setSelectedCategory(category)">
        <span [ngClass]="{ selectedLabel: isSelected(category) }">{{ category | agReplace: "_":" " }}</span>
        <div *ngIf="category === BlockCategory.RATE_MAKING" >ALPHA</div>
      </button>
    </mat-menu>
  </div>
  <ng-container *ngFor="let operationCategory of getOperations(); let lastItem = last">
    <ng-container *ngFor="let operation of operationCategory">
      <button *ngIf="operation.subOperations.length === 0"
              mat-icon-button
              
              id="operation-icon-{{ operation.value }}"
              (click)="addOperation(operation.value)"
              [disabled]="operation.disabled$ | async">
        <mat-icon [ngClass]="operation.icon"  [agToolTip]="operation.tooltip$ | async"></mat-icon>
      </button>
      <ng-container *ngIf="operation.subOperations.length !== 0">
        <button
          mat-button
          mat-icon-button
          
          id="operation-menu-icon-{{ operation.value }}"
          [matMenuTriggerFor]="subMenu">
          <mat-icon [ngClass]="operation.icon"  [agToolTip]="operation.tooltip$ | async"></mat-icon>
        </button>
        <mat-menu #subMenu="matMenu">
          <button mat-menu-item>Settings</button>
          <button mat-menu-item>Log off</button>
        </mat-menu>
      </ng-container>
    </ng-container>
    <div  *ngIf="!lastItem"></div>
  </ng-container>
</div>

I have created a stackblitz reproducing the issue: https://angular-ivy-cvv2xk.stackblitz.io

The issue is that when I click on the button, nothing happens. When I move the button out of the ngFor loops though, it works properly. I have tried things such as removing the ngIf condition (so all buttons are doubled) and none show the menu when clicking on it. So the "submenu" is never displayed.

I wonder if I need to make the mat-menu specific or give it some id to ensure there are no conflicts? Since I'm a bit new to Angular I maybe be missing something.

Thanks in advance

CodePudding user response:

Your button which triggers submenu got multiple button tags.

<button
      mat-button
      mat-icon-button

Can you remove one and try again?


Edit:

You use <ng-container *ngFor="let operationCategory of getOperations(); to populate your array.

If you press your button, angular will trigger change detection and this will trigger again your getOperations(). This will lead to this behaviour and dosent open your submenu.

So you should try to replace getOperations() with async pipe (if this is the case) or use properties.

  • Related