Reputation: 10844
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
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
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