Components: Provide a way to attach Content Projected mat-menu-items to existing mat-menu

Created on 7 Jan 2020  路  5Comments  路  Source: angular/components

I'm not sure if this should be a bug-report or a feature request, but I'll let you guys categorize it properly.

Feature Description

Let's say we have a generic component containing some standard menu items, and we want to allow users of this component to add their own custom menu items. There is no way to add content projected menu-items as proper children of the "internal" menu. If mat-menu-items are provided as <ng-content> to the component defining the <mat-menu>, the items are detached from the <mat-menu>

Use Case

widget.component.ts

@Component({
  selector: 'app-widget',
  templateUrl: './widget.component.html',
  styleUrls: ['./widget.component.scss']
})
export class WidgetComponent implements AfterViewInit {
  // The matMenu all the items should be connected to
  @ViewChild('actionsMenu', {static: false}) actionsMenu: MatMenu;

  // The matMenuItem's inserted into this component externally
  @ContentChildren(MatMenuItem) menuItems: QueryList<MatMenuItem>;

  constructor() { }

  ngAfterViewInit() {
    // By listing out these, I find that none of them have `_parentMenu` set.
    console.log(this.menuItems);
  }
}

widget.component.html

<!-- The menu trigger -->
<button mat-icon-button [matMenuTriggerFor]="actionsMenu">
  <mat-icon>more_vert</mat-icon>
</button>

<!-- The menu -->
<mat-menu #actionsMenu="matMenu">
  <button mat-menu-item type="button" (click)="doStuff()">
    Standard 1
  </button>
  <button mat-menu-item type="button" (click)="doSomethingElse()">
    Standard 2
  </button>

  <!-- Insert dynamic items -->
  <ng-content select="[app-widget-actions]"></ng-content>
</mat-menu>

app.component.html

<app-widget>

  <!-- Actions menu -->
  <ng-container app-widget-actions>
    <button mat-menu-item [matMenuTriggerFor]="custom">
      Custom task
    </button>
    <mat-menu #custom="matMenu">
      <button mat-menu-item type="button">Custom task 1</button>
      <button mat-menu-item type="button">Custom task 2</button>
    </mat-menu>
  </ng-container>

</app-widget>

This will render the widget and all content fine. But the "Custom task" menu item defined in app.component.html will not render as a submenu (which should open to the side on hover). I would expect the above to produce the following menu structure:

- Menu
  |- Standard 1
  |- Standard 2
  |- Custom task
     |- Custom task 1
     |- Custom task 2

Instead it produces:

- Menu
  |- Standard 1
  |- Standard 2
  |- Custom task

where the "Custom task" will only react on click (like a mat-menu without a parent menu).

Request

Preferably I would like angular material to just fix this, but if this is problematic I would like to loop over these menuItems and attach them to the given actionsMenu somehow. I would expect the actionsMenu.addItem(item) to do this, but the attached items are all without a parentMenu after I try this. And for given menu-items with submenus, the _triggersSubmenu is always false.

Can you please provide a way to allow content-projected menu-items inside a MatMenu?

materiamenu feature needs triage

Most helpful comment

Looks like it's well known bug without fix. With @YuriyDetsyk we have found the way of use that maybe can meet your needs.

menu.component.html

...
<button [matMenuTriggerFor]="menu"> Open Menu </button>
...

menu.component.ts

...
@Component({
    selector: "extended-material-menu",
...
@Input() menu: MatMenu;
...

app.component.html

...
<extended-material-menu [menu]="menu">
    <mat-menu #menu="matMenu">
         <button mat-menu-item> Menu Item </button>
    </mat-menu>
</extended-material-menu>
...

All 5 comments

Indeed, the lack of proper content projection support in the <mat-menu> component also causes other side effects. One of them is not being able to navigate through menu items with the keyboard.

Looks like it's well known bug without fix. With @YuriyDetsyk we have found the way of use that maybe can meet your needs.

menu.component.html

...
<button [matMenuTriggerFor]="menu"> Open Menu </button>
...

menu.component.ts

...
@Component({
    selector: "extended-material-menu",
...
@Input() menu: MatMenu;
...

app.component.html

...
<extended-material-menu [menu]="menu">
    <mat-menu #menu="matMenu">
         <button mat-menu-item> Menu Item </button>
    </mat-menu>
</extended-material-menu>
...

I have a similar issue using ng-content to get mat-menu-item elements. @mmalerba any plans for adding this in the near future?

This is an issue that needs to be considered at the framework level, see https://github.com/angular/angular/issues/37319

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jelbourn picture jelbourn  路  3Comments

kara picture kara  路  3Comments

LoganDupont picture LoganDupont  路  3Comments

xtianus79 picture xtianus79  路  3Comments

theunreal picture theunreal  路  3Comments