Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material 2 MatMenu - Dynamically creation

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?

like image 566
julianobrasil Avatar asked May 25 '17 00:05

julianobrasil


People also ask

What is matMenuTriggerFor?

matMenuTriggerFor is passed the menu identifier to attach the menus.

How to change mat menu position?

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.

How do I stop mat menu from closing?

stoppropagation() on each mat-menu-item to prevent it from closing.


1 Answers

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>

Another approach

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.

like image 127
julianobrasil Avatar answered Oct 16 '22 04:10

julianobrasil