I need to dynamically create a bunch of MatMenu
. So far I have no idea of how I can:
1 - Create a template reference variable dynamically (for the mat-menu
component)
2 - Reference the dynamically created variable (to use in the [matMenuTriggerFor]
attribute of the trigger)
I've searched a little and found nothing about it.
Does anyone manage do deal with it?
matMenuTriggerFor is passed the menu identifier to attach the menus.
Changing mat menu position If you want the menu to display before or after the menu trigger element, set the xPosition value to "before" or "after." Set the xPosition value to "before" or "after" if you just want the menu to appear before or after the menu trigger element.
stoppropagation() on each mat-menu-item to prevent it from closing.
Solved by encapsulating the MatMenu
and the associated trigger in an Angular custom component.
Scenario: There's an array of objects that must be shown in a table. The last column of the table must show the MatMenu
with two options: Edit and Delete.
So I made a custom angular component containing just the MatMenu
and its trigger inside it. This component uses two-way data bind to receives the object that must be edited/deleted and proceed with the desired action:
If the purpose is to edit, shows a dialog to edit the data
If the purpose is to delete, it deletes the data
Once the action is completed, the host of the custom component must perform one of two actions:
1 - update the array replacing/deleting the edited/removed element
2 - update the entire array, asking for all its forming data again from the server
In both cases, you'll have to monitor the changes and do any updates in the array whenever the update/deletion is finished. An alternative is to create another two-way data bound variable and pass the entire array as a two-way data-bound parameter to the custom component.
I built up this Stackblitz to better show it: https://stackblitz.com/edit/repeating-menu-approach-1
<table>
<tr *ngFor="let el of [1,2,3,4,5]">
<td>Text line of menu {{el}}</td>
<td style="width: 5%">
<menu-overview-example [x]="el" (clickedItem)="hostClickHandler($event)"></menu-overview-example>
</td>
</tr>
</table>
There's one more way to do it: you can use <ng-container>
and it will just create a scope for your template variable (https://stackblitz.com/edit/repeating-menu-approach-2):**
<table>
<ng-container *ngFor="let el of [1,2,3,4,5]">
<tr>
<td>Text line of menu {{el}}</td>
<td style="width: 5%">
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="clickHandler('Item 1 of Menu ' + el)">Menu {{el}}:Item 1</button>
<button mat-menu-item (click)="clickHandler('Item 2 of Menu ' + el)">Menu {{el}}:Item 2</button>
</mat-menu>
</td>
</tr>
</ng-container>
</table>
Interestingly, each #menu
template variable above will be unique, fully isolated from the others #menu
template variables created by the *ngFor
loop.
[UPDATE]: As a matter of fact, you can drop the <ng-container>
and use the *ngFor
directly on the <tr>
element along with the #menu
template variable. The isolated scope will be created in the same way as described above. But as I think it's more comprehensible for angular new users the presence of ng-container
, I decided to keep it on this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With