Mauricio Gracia Gutierrez
Mauricio Gracia Gutierrez

Reputation: 10844

Click function not being called for a mat-menu with items generated with ngFor

I'm having issues implementing a mat-menu with a *ngfor

I've checked this answer How can i use *ngFor with mat-menu and mat-menu-item? and I believe that I'm following the same approach but I still get errors

The render HTML relevant part is this

<div id="cdk-overlay-1" class="cdk-overlay-pane" style="pointer-events: auto; top: 451.766px; right: -6px;">
   <div tabindex="-1" role="menu" class="mat-menu-panel ng-trigger ng-trigger-transformMenu ng-tns-c53-4 mat-menu-below ng-star-inserted mat-elevation-z4 mat-menu-before" id="mat-menu-panel-0" ng-reflect-ng-class="[object Object]" style="transform-origin: right top;">
      <div class="mat-menu-content ng-tns-c53-4">
         <div _ngcontent-gka-c557="" class="ng-star-inserted" style="">
            <button _ngcontent-gka-c557="" mat-menu-item="" class="mat-focus-indicator mat-menu-item" role="menuitem" tabindex="0" aria-disabled="false">
               Order history
               <div matripple="" class="mat-ripple mat-menu-ripple" ng-reflect-disabled="false" ng-reflect-trigger="[object HTMLButtonElement]"></div>
            </button>
         </div>
        *<!--**bindings={
            "ng-reflect-ng-for-of": "[object Object]"
            }**-->
      </div>
   </div>
</div>

To my understanding when angular has issues with rendering an element it shows the

ng-reflect-ng-for-of": "[object Object]

This is the Angular HTML source code

<span class='icm'>
    <button mat-icon-button [matMenuTriggerFor]="menu">
        <mat-icon fontSet="material-icons-outlined" class="aligned-icon">
            {{iconName}}
        </mat-icon>
        <mat-menu #menu="matMenu">
            <div *ngFor="let menuItem of this.menuItems">
                <button mat-menu-item  (click)="handleMenuItemClick(menuItem)">{{menuItem.description}}</button> 
            </div>
        </mat-menu>
    </button>
</span>

The menu itself is showing fine, but when I try to click on the item, nothing happens

I have tried placing each item in a ng-template and also on its own component with same problem as before.

What can be causing this ?

Here is the Typescript file for IconContextMenuComponent

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';

export interface IconMenuOption {
  id: number;
  description: string;
}
export interface MenuOptionSelectedEvent {
  id: any;
  selectedMenuOption: IconMenuOption
}

@Component({
  selector: 'wss-icon-context-menu',
  templateUrl: './icon-context-menu.component.html',
  styleUrls: ['./icon-context-menu.component.scss']
})

export class IconContextMenuComponent implements OnInit {

  constructor() { }
  @Input() id: any;
  @Input() iconName: string;
  @Input() menuItems: IconMenuOption[] = [];
  @Output() menuItemSelected = new EventEmitter();

  ngOnInit() {
  }


  public handleMenuItemClick(menuitem: IconMenuOption) {
    const menuOptionSelectedEvent: MenuOptionSelectedEvent = {
      id: this.id,
      selectedMenuOption: menuitem
    };

    console.log({ menuOptionSelectedEvent: menuOptionSelectedEvent });
    this.menuItemSelected.emit(menuOptionSelectedEvent);
  }

}

UPDATE

I have also tried in this way, with the same results

<span class='icm'>
    <button mat-icon-button [matMenuTriggerFor]="menu">
        <mat-icon fontSet="material-icons-outlined" class="aligned-icon">
            {{iconName}}
        </mat-icon>
    </button>
    <mat-menu #menu="matMenu">
        <button mat-menu-item *ngFor="let menuItem of this.menuItems"
            (click)="handleMenuItemClick(menuItem)">{{menuItem.description}}</button>
    </mat-menu>
</span>
``` html

  [1]: https://i.sstatic.net/RoCEr.png

Upvotes: 3

Views: 3806

Answers (2)

Yoann ROCHE
Yoann ROCHE

Reputation: 128

this one worked for me

Adding trackBy on ngFor

HTML:

  <mat-menu #menu="matMenu">
     <ng-container *ngFor="let action of globalMenuAction; trackBy: trackActions">

ts :

 trackActions(index: number, action: ActionItem): string {
    return action.id;
  }

UPDATE : now you can use @for(action of globalMenuAction; track action.id)

Upvotes: 4

Mauricio Gracia Gutierrez
Mauricio Gracia Gutierrez

Reputation: 10844

The solution is to have an internal variable in the component that is assigned from the Input() variable

@Input() menuItems: IconMenuOption[] = [];

internalItems: IconMenuOption[]

ngOnInit() {
  this.internalItems = this.menuItems;
}

And bind the menu-options (component items) from the internal component variable and not from the input parameter.

<mat-menu #menu="matMenu">
    <button mat-menu-item *ngFor="let mi of internalItems" (click)="handleMenuItemClick(mi)">{{mi.description}}</button>
</mat-menu>

Upvotes: 5

Related Questions