TmTron
TmTron

Reputation: 19441

How to include a full mat-menu in a parent menu?

We want to split a large menu (e.g. like the Nested menu example from the material components docs) into separate smaller components.

E.g. in this Stackblitz example we moved the fish menu to a separate component: fish-menu.component.ts:

import { Component } from "@angular/core";

@Component({
  selector: "fish-menu",
  template: `
    <button mat-menu-item [matMenuTriggerFor]="fish">Fishes</button>

    <mat-menu #fish="matMenu">
      <button mat-menu-item>Baikal oilfish</button>
      <button mat-menu-item>Bala shark</button>
      <button mat-menu-item>Ballan wrasse</button>
      <button mat-menu-item>Bamboo shark</button>
      <button mat-menu-item>Banded killifish</button>
    </mat-menu>
  `
})
export class FishMenuComponent {}

And include it in the parent menu, like so:

<button mat-button [matMenuTriggerFor]="animals">Animal index</button>

<mat-menu #animals="matMenu">
  <button mat-menu-item [matMenuTriggerFor]="vertebrates">Vertebrates</button>
  <button mat-menu-item [matMenuTriggerFor]="invertebrates">Invertebrates</button>
</mat-menu>

<mat-menu #vertebrates="matMenu">
  <!-- our child-component does not work as expected -->
  <fish-menu></fish-menu>
  <!-- other children are okay -->
  <button mat-menu-item [matMenuTriggerFor]="amphibians">Amphibians</button>
  <!-- etc. -->

But the included menu does not work as expected, when we hoover the menu item:

  1. the fish menu is not opened (unless we click it)
  2. the other menus are not closed (when the fish menu is opened)

NOTE
We want to include the full menu in the child component: i.e. the button with matMenuTriggerFor and the related mat-menu (because the very same menu should be included in multiple places in the production app). And the parent menu is not always the same: i.e. we have many different parent-menus which are composed of different sub-menus.

How can we make this work as expected?

Upvotes: 1

Views: 1898

Answers (1)

robbieAreBest
robbieAreBest

Reputation: 1771

I've run into this issue as well and this is caused by your child component not having the same context for matMenu as your parent. To work around this I passed an object of my child menus to my parent through an input and built them dynamically.

If you are planning to have a single component that displays your matMenuTriggerFor button I believe your solution should be much more straightforward. You can house your entire menu in a single component and use it in multiple other components.

I've done something like what you described here: https://stackblitz.com/edit/angular-me42ci-bbbnfz?file=src%2Fapp%2Fmenu-nested-example.html


EDIT

I came up with something that might work for you. You could pass in your top level menu items through ng-content:

<app-menu>
  <button mat-menu-item>Aliens</button>
</app-menu>

menu.component.ts:

  <mat-menu #animals="matMenu">
    <ng-content></ng-content>
    <button mat-menu-item [matMenuTriggerFor]="vertebrates">
      Vertebrates
    </button>
    <button mat-menu-item [matMenuTriggerFor]="invertebrates">
      Invertebrates
    </button>
  </mat-menu>

https://stackblitz.com/edit/angular-me42ci-bbbnfz?file=src%2Fapp%2Fmenu-nested-example.html

Upvotes: 2

Related Questions