Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing data to mat-menu

My 'awesome' menu:

<mat-menu #appMenu="matMenu">
  <ng-template matMenuContent let-myobject="myobject">
    <button mat-menu-item>Delete {{myobject.name}}</button>
    <button mat-menu-item>Smth else</button>
  </ng-template>
</mat-menu>

<button mat-icon-button [matMenuTriggerFor]="appMenu" [matMenuTriggerData]="{myobject: myobject}">
   <mat-icon>more_vert</mat-icon>
</button>

First question is if it is ok? Wrote this following documentation but let-myobject="myobject" and {myobject: myobject} looks like overhead (?)

Second question is if I want to calculate some data based on myobject - how I do that? I want it to be calculated just before menu is opened.

[matMenuTriggerData]="getData(myobject)" - cant make this or similar work

<ng-template matMenuContent let-data="getData(myobject)"> - cant make this or similar work either

I know that I can replace ng-template with component here, but then for e.g. 10 menu items I will need to do 10 outputs in this component. (? or I cant...)

like image 302
Petr Averyanov Avatar asked Mar 26 '19 16:03

Petr Averyanov


1 Answers

You can certainly pass an object to a mat-menu by using the matMenuTriggerData directive. This object can contain a single value, another object, or even an array of values or objects. Here's how I solved it:

My challenge was this: I wanted to dynamically build a list of menu items (mat-menu-item) based on the contents of an array. How did I manage to pass that array of objects to my mat-menu?

In your component class you can define the array of objects:

    export class MyComponent implements OnInit {
      menuData: any;

      ngOnInit() {
        this.menuData = {
          menuItems: [
            {code: '1', name: 'first'},
            {code: '2', name: 'second'}
          ]
        };
      }
    }

Notice that the object I will pass to the matMenuTriggerData directive of the button that opens the mat-menu content, is the data member called menuData. This member has only one property which is an array of objects. These represent the actual menu items I want to display in my template. The template is shown below:

    <mat-menu #app-menu="matMenu">
      <ng-template matMenuContent let-aliasMenuItems="menuItems">
        <button mat-menu-item *ngFor="let item of aliasMenuItems">
          Item {{item.code}}: {{item.name}}
        </button>
      </ng-template>
    </mat-menu>
    <button mat-icon-button [matMenuTriggerFor]="app-menu" [matMenuTriggerData]="menuData">
      <mat-icon>more_vert</mat-icon>
    </button>

Let me explain what is going on in the template: The button defined in the bottom of the template has been linked to the mat-menu called 'app-menu'. This is done by typing [matMenuTriggerFor]="app-menu".

The next thing we do is passing the component's member data to the mat-menu through this directive: [matMenuTriggerData]="menuData". The mat-menu instance that we named app-menu can now grab the content of that member data.

As you can see, the <ng-template> accesses the property of 'menuData' that we have named 'menuItems'. The <ng-template> adds a pointer or alias to that property (called aliasMenuItems), like this: <ng-template let-aliasMenuItems="menuItems">. Now we are able to loop through our defined array of menu items inside the <ng-template>.

In my example, I create a <button mat-menu-item></button> element for each menu item object that exists in my component's menuData.menuItems array, like this:

    <button mat-menu-item *ngFor="let item of aliasMenuItems">
      Item {{item.code}}: {{item.name}}
    </button>

I hope you find this answer useful.

like image 78
Ittit Avatar answered Oct 01 '22 05:10

Ittit