I have a complex MatMenu
with more MatMenuItem
. Each MatMenuItem
's visibility is based on a condition. The trigger button is disabled if all possible condition are false, eg.:
<button mat-button [matMenuTriggerFor]="menu" [disable]="!condition1 && !condition2 && !condition3 && !conditionN">Menu</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngIf="condition1">Item 1</button>
<button mat-menu-item *ngIf="condition2">Item 2</button>
<button mat-menu-item *ngIf="condition3">Item 3</button>
...
<button mat-menu-item *ngIf="conditionN">Item N</button>
</mat-menu>
There are a simple way for check if a MatMenu
has at least one MatMenuItem
and disable the trigger button if no one MatMenuItem
are available?
items
As mentioned in previous answer, one potential solution could be to use items
of exported matMenu
.
But we will have 2 issues :
items
property is deprecated, and could be removed soon./**
* List of the items inside of a menu.
* @deprecated
* @breaking-change 8.0.0
*/
items: QueryList<MatMenuItem>;
disabled
property with matMenu.items.length
will throw a NG0100 error if we are in default change detection strategy (not in OnPush), because change detection process is not finished.To solve this, we can create a reusable directive, which will query MatMenuItem
of a MatMenu
, and then fire an event with the current status of menu : true
if at least one option, false
if not.
menu-toggled.directive.ts:
@Directive({
selector: 'mat-menu',
})
export class MenuToggledDirective implements AfterContentInit, OnDestroy {
_destroyed$ = new Subject<void>();
@ContentChildren(MatMenuItem, { descendants: true })
_items!: QueryList<MatMenuItem>;
@Output()
menuToggled = new EventEmitter<boolean>();
ngAfterContentInit(): void {
this._items.changes
.pipe(
takeUntil(this._destroyed$),
startWith(0),
map((_) => this._items.length > 0)
)
.subscribe(this.menuToggled);
}
ngOnDestroy(): void {
this._destroyed$.next();
this._destroyed$.complete();
}
}
Usage in app.component.html :
<button #button mat-stroked-button [mat-menu-trigger-for]="menu">
Menu
</button>
<mat-menu #menu="matMenu" (menuToggled)="button.disabled = !$event">
<button mat-menu-item *ngIf="flag">Item 1</button>
<button mat-menu-item *ngIf="false">Item 2</button>
</mat-menu>