11

MenuItem of primeng has a parameter called command that is a function to be executed when its item is clicked. One example of using this is provided in https://www.primefaces.org/primeng/#/steps to give feedback to user.

command: (event: any) => {
                this.activeIndex = 0;
                this.msgs.length = 0;
                this.msgs.push({severity:'info', summary:'First Step', detail: event.item.label});
            }

However, I want to use the MenuItem as a column of my Primeng DataTable, like this.

enter image description here

And for this I need to use my menu this way:

<p-column>
  <ng-template let-item="rowData"
      <p-menu #menu popup="popup" [model]="items"></p-menu>
      <button type="button" pButton icon="fa fa-list" label="Show" (click)="menu.toggle($event)"></button>
  </ng-template>
</p-column>

To get "item" and the row that I'm clicking and other kind of data.

Using a buttom I can pass item and other data through onClick, but for this I need to create one column for each buttom. And to solve that I want to use Menu with MenuItem from primeng.

The problem is that I can't find any examples passing parameters through a command in MenuItem and I'm not find a way to do it.

How can I accomplish that using MenuItem with DataTable?

If that is not possible, how can I accomplish the same results?

sabithpocker
  • 15,274
  • 1
  • 42
  • 75
Gabriel Costa
  • 349
  • 1
  • 4
  • 13
  • You got a stackblitz or plunker for this? – Chau Tran Nov 29 '17 at 19:45
  • @ChauTran I dont have a plunker but I found a workaround. If you have any doubts of the problem I'm here to help you understand. Thanks for you attention to the question. – Gabriel Costa Nov 29 '17 at 20:06
  • Possible duplicate of [PrimeNg context menu passing data issue](https://stackoverflow.com/questions/51480381/primeng-context-menu-passing-data-issue) – Ravindra Vairagi Jul 12 '19 at 11:50

7 Answers7

14

You can have a function that takes rowData and returns contextual MenuItem[]

<p-column>
  <ng-template let-item="rowData"
      <p-menu #menu popup="popup" [model]="getMenuItemsForItem(item)"></p-menu>
      <button type="button" pButton icon="fa fa-list" label="Show" (click)="menu.toggle($event)"></button>
  </ng-template>
</p-column>

  getMenuItemsForItem(item: MyItem): MenuItem[] {
    const context = item;
    return [
      { label: 'Label1', icon: 'fa-plus', command: e => this.takeAction(e, context) }
    ]
  }

UPDATE

[model]="getMenuItemsForItem(item)"

can cause performance issues, should be using a binding to an object instead.

[model]="menuItems[item.uniqueKey]"

and then set menuItems object with menu items for each item.

sabithpocker
  • 15,274
  • 1
  • 42
  • 75
  • I have had problems generating menu items on demand. Specifically each menu item's click event fails to fire when you click on it. So you need to generate the menu items and then cache the resulting array until they need to be changed, or do what you suggested in your update. – user169771 Sep 26 '22 at 19:09
7

I know this is old but one thing that could prevent having to have NN p-menu directives in your page would be to call a function from your component on button click instead of (click)="menu.toggle($event)" and in that function inject the data on each menu item.

I know this is kind of hacky but it's better than to replicate a p-menu for every table row.

Here is an example :

<p-menu #popupMenu [popup]="true" [model]="menuItems"></p-menu>

<!-- and where you want to open the menu -->
<a *ngIf="itemsMenu" (click)="toggleMenu(popupMenu, $event, rowData)">
    <i class="fas fa-chevron-circle-down"></i>
</a>
 toggleMenu(menu, event, rowData) {
    this.menuItems.forEach((menuItem) => {
      menuItem.data = rowData;
    });
    menu.toggle(event);
  }

Regards

Mathieu de Lorimier
  • 975
  • 3
  • 19
  • 32
3

I found a way to solve the problem, although I think that it's not the best solution. I hope that those who are with the same problem can find it helpful.

Passing the table item via onClick and populating the menuItems with the callback works.

Sample:

Html

    <p-column>
      <ng-template let-item="rowData"
          <p-menu #menu popup="popup" (onClick)="onClickMenu(item)" [model]="items"></p-menu>
          <button type="button" pButton icon="fa fa-list" label="Show" (click)="menu.toggle($event)"></button>
      </ng-template>
    </p-column>

Typscript

    onClickMenu(item: any){

      this.items.push({label: 'Option 1',
                      command: (event: any) => {
                      doSomething(item);}
                      });

      this.items.push({label: 'Option 2',
                      command: (event: any) => {
                      doSomething(item);}
                      });

      this.items.push({label: 'Option 3',
                      command: (event: any) => {
                      doSomething(item);}
                      });
                    
    }
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Gabriel Costa
  • 349
  • 1
  • 4
  • 13
1

JS

this.items = (rowData) => {
  return [
    {
      label: 'Certidão', icon: 'ui-icon-print', command: (event) => {
        console.log(rowData);
      }
    },
    {
      label: 'Declaração', icon: 'ui-icon-print', command: (event) => {
        console.log(rowData);
      }
    }
  ];
};

HTML

<p-splitButton label="{{ rowData.nomeColaborador }}" icon="ui-icon-folder" [model]="items(rowData)" >

If you want to pass a rowData you can explicit a function call like this

1

Another option is to add the current menu rowData to a private variable upon menu selection like so:

<p-menu #menu popup="popup" [model]="items"></p-menu>
      <button type="button" class="btn-more" pButton icon="icon-more" label=" " (click)="menu.toggle($event);onClickMenu(rowData);"></button>

public onClickMenu(rowData: any) { 
        this.currentRowData = rowData; 
    }

Let me know if there are any repercussions in doing it this way, thanks.

vicgoyso
  • 636
  • 1
  • 14
  • 35
1

Easier and cleaner solution:

Data table:

<td>
    <i class="pi pi-ellipsis-h" style="cursor: pointer" (click)="activeItem = rowData;menu.toggle($event)"></i>
</td>
<p-menu #menu [popup]="true" [model]="menuItems"></p-menu>

Set active row and open menu (click)="activeItem = rowData;menu.toggle($event)"

component.ts:

activeItem:any;

this.menuItems = [
      {
        label: 'Details',
        icon: 'pi pi-eye',
        command: (e) => {
          console.log(this.activeItem);
          // logic
        }
      }
    ];
Danail Videv
  • 763
  • 6
  • 16
0

I fixed the problem by adding an id to the p-menu element. Then I retrieve that value from the event of the command method.

HTML:

 <p-menu #menu [id]={{myValue}} popup="true" [model]="items">.   </p-menu>

TS:

items = [{ label: 'Label1', icon: 'fa-plus', command: e => this._myFunction(e) }]
private _myFunction(e) { 
  const myValue = event.originalEvent.path.find((element: any) => element.nodeName === 'P-MENU').id;
  console.log(myValue)
}

Hope this can help you.

Fiehra
  • 659
  • 6
  • 23
FreeCoder
  • 1
  • 2