I need a Context Menu per row mat-table with multiple submenus. How I can add custom menu with multiple submenu? I need to use Angular 11 and Angular Material 11.
Could you help me with this code?
This is my current code and I can only use the main submenu
HTML file
<td
mat-cell
*matCellDef="let row"
class="custom-table-cell"
[style.width]="columnsConfiguration[column].width"
(contextmenu)="
currentTableOptions.showMenuActions &&
currentRowMenuActions.length &&
onContextMenu(row, $event)
">
...
<!-- START Menu per row -->
<span
#contextMenuTrigger
style="visibility: hidden; position: fixed"
[style.left]="contextMenuPosition.x"
[style.top]="contextMenuPosition.y"
[matMenuTriggerFor]="contextMenu"
(menuOpened)="hasContextMenu = true"
(menuClosed)="hasContextMenu = false"></span>
<mat-menu
#contextMenu="matMenu"
backdropClass="actions-selector-menu-backdrop"
class="actions-selector-menu">
<ng-template
matMenuContent
let-row="row">
<button
mat-menu-item
*ngFor="let rowMenuAction of currentRowMenuActions"
(click)="onRowMenuAction(row, rowMenuAction, $event)"
[disabled]="
rowMenuAction.isDisabled ? rowMenuAction.isDisabled(row) : false
">
{{ rowMenuAction.translateKey | translate }}
</button>
</ng-template>
</mat-menu>
<!-- END Menu per row -->
TS file. I create a contextmenu content
// Menu per row
@ViewChild('contextMenuTrigger', { read: MatMenuTrigger })
contextMenu!: MatMenuTrigger;
contextMenuPosition = { x: '0px', y: '0px' };
onContextMenu(row: T, event: MouseEvent) {
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.contextMenu.menuData = { row };
this.contextMenu.menu.focusFirstItem('mouse');
this.contextMenu.openMenu();
}
// Actions per menu row
@Input() set rowMenuActions(value: RowMenuAction<T>[]) {
this.currentRowMenuActions = value;
}
currentRowMenuActions: RowMenuAction<T>[] = [];
@Output() rowMenuAction = new EventEmitter<RowMenuActionEvent<T>>();
onRowMenuAction(row: T, action: RowMenuAction<T>, event: Event) {
this.rowMenuAction.emit({ row, action, event });
}
Thanks!
Solution is the next:
context-menu.component.html
<mat-menu
#menu="matMenu"
backdropClass="actions-selector-menu-backdrop"
class="actions-selector-menu"
[overlapTrigger]="false">
<ng-template
matMenuContent
let-row="row">
<ng-container *ngFor="let rowMenuAction of currentRowMenuActions">
<!-- Handle branch node menu items -->
<ng-container
*ngIf="rowMenuAction.children && rowMenuAction.children.length > 0">
<button
mat-menu-item
color="primary"
[matMenuTriggerFor]="submenu.menu"
[matMenuTriggerData]="{ row: row }">
{{ rowMenuAction.translateKey | translate }}
</button>
<talan-context-menu
#submenu
[rowMenuActions]="rowMenuAction.children"
(rowMenuAction)="onRowMenuAction($event)"></talan-context-menu>
</ng-container>
<!-- Handle leaf node menu items -->
<button
*ngIf="!rowMenuAction.children || rowMenuAction.children.length === 0"
mat-menu-item
(click)="
onRowMenuAction({ row: row, action: rowMenuAction, event: $event })
"
[disabled]="
rowMenuAction.isDisabled ? rowMenuAction.isDisabled(row) : false
">
{{ rowMenuAction.translateKey | translate }}
</button>
</ng-container>
</ng-template>
</mat-menu>
context-menu.component.ts
import {
Component,
EventEmitter,
Input,
Output,
ViewChild,
} from '@angular/core';
import { MatMenu } from '@angular/material/menu';
import { RowMenuAction, RowMenuActionEvent } from '../../models/models';
@Component({
selector: 'talan-context-menu',
templateUrl: './context-menu.component.html',
styleUrls: ['./context-menu.component.scss'],
})
export class ContextMenuComponent<T> {
@ViewChild('menu', { static: true }) menu!: MatMenu;
// Actions per menu row
@Input() set rowMenuActions(value: RowMenuAction<T>[]) {
this.currentRowMenuActions = value;
}
currentRowMenuActions: RowMenuAction<T>[] = [];
@Output() rowMenuAction = new EventEmitter<RowMenuActionEvent<T>>();
onRowMenuAction(event: RowMenuActionEvent<T>) {
this.rowMenuAction.emit(event);
}
}
table.component.html
<td
mat-cell
*matCellDef="let row"
(contextmenu)="
onContextMenu(row, $event)">
<span
#contextMenuTrigger="matMenuTrigger"
style="visibility: hidden; position: fixed"
[style.left]="contextMenuPosition.x"
[style.top]="contextMenuPosition.y"
[matMenuTriggerFor]="contextMenu.menu"
(menuOpened)="hasContextMenu = true"
(menuClosed)="hasContextMenu = false"></span>
<context-menu
#contextMenu
[rowMenuActions]="currentRowMenuActions"
(rowMenuAction)="onRowMenuAction($event)"></context-menu>
table.component.ts
@ViewChild('contextMenuTrigger') contextMenuTrigger!: MatMenuTrigger;
@ViewChild('contextMenu') contextMenu!: ContextMenuComponent<T>;
contextMenuPosition = { x: '0px', y: '0px' };
onContextMenu(row: T, event: MouseEvent) {
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.contextMenuTrigger.menu.focusFirstItem('mouse');
this.contextMenuTrigger.menuData = { row };
this.contextMenuTrigger.openMenu();
}