简体   繁体   中英

Angular 5 Material Multiple mat-menu

I am quite new to Angular 5 and have just started learning it.

Recently, I have been trying to create a menu bar with multiple menus for my app using Angular 5 Material.
The menu will be triggered/opened during mouse enter and closed when the mouse leaves the menu.
My problem is that everytime the mouse mouse hovers to the first menu it loads the menu items of the 2nd menu.

Here is a screenshot of the problem:
在此处输入图片说明

Here are my codes:
mainmenu.component.html :

<div>
    <button mat-button [matMenuTriggerFor]="menu1" 
      (mouseenter)="openMyMenu()">Trigger1</button>
    <mat-menu #menu1="matMenu" overlapTrigger="false">
        <span (mouseleave)="closeMyMenu()">
            <button mat-menu-item>Item 1</button>
            <button mat-menu-item>Item 2</button>
        </span>
   </mat-menu>
</div>
<div>
    <button mat-button [matMenuTriggerFor]="menu2"
      (mouseenter)="openMyMenu()">Trigger2</button>
    <mat-menu #menu2="matMenu" overlapTrigger="false">
        <span (mouseleave)="closeMyMenu()">
            <button mat-menu-item>Item 3</button>
            <button mat-menu-item>Item 4</button>
        </span>
    </mat-menu>
</div>



mainmenu.component.ts :

import { Component, OnInit, ViewChild } from '@angular/core';
import {MatMenuTrigger} from '@angular/material'

@Component({
  selector: 'app-mainmenu',
  templateUrl: './mainmenu.component.html',
  styleUrls: ['./mainmenu.component.css']
})
export class MainmenuComponent implements OnInit {
  @ViewChild(MatMenuTrigger) matMenuTrigger: MatMenuTrigger;

  constructor() { }

  ngOnInit() {
  }
  openMyMenu() {
    this.matMenuTrigger.openMenu();

  } 
  closeMyMenu() {
    this.matMenuTrigger.closeMenu();
  }
}

I also tried this: @ViewChild('menu1') matMenuTrigger: MatMenuTrigger; but I am getting errors.
Your opinions and advices are very much appreciated!


Thanks,
Artanis Zeratul

References:


The correct solution for this problem:

@ViewChildren(MatMenuTrigger) trigger: QueryList<MatMenuTrigger>;

//And call:

me.trigger.toArray()[indexOfMenu].openMenu();

I had the same issue.

Create two separate components, each will then contain its own mat-menu and will not affect the other.

<!-- component1 -->
<div>
 <button mat-button [matMenuTriggerFor]="menu1" 
  (mouseenter)="openMyMenu()">Trigger1</button>
 <mat-menu #menu1="matMenu" overlapTrigger="false">
    <span (mouseleave)="closeMyMenu()">
        <button mat-menu-item>Item 1</button>
        <button mat-menu-item>Item 2</button>
    </span>
</mat-menu>
</div>

<!-- component2 -->
<div>
<button mat-button [matMenuTriggerFor]="menu2"
  (mouseenter)="openMyMenu()">Trigger2</button>
<mat-menu #menu2="matMenu" overlapTrigger="false">
    <span (mouseleave)="closeMyMenu()">
        <button mat-menu-item>Item 3</button>
        <button mat-menu-item>Item 4</button>
    </span>
 </mat-menu>
</div>

I have two matmenus in my toolbar each one is a separate component and triggers a separate matmenu.

See images below:

在此处输入图片说明

Here is my notifications component(component 1 in the image above) In my editor view :

在此处输入图片说明

In my notifications.component.html file :

<button mat-icon-button [matMenuTriggerFor]="notificationsMenu" (mouseover)="openNotifications()">
  <mat-icon class="material-icons ele-text-color-grey">notifications</mat-icon>
</button>

<mat-menu #notificationsMenu="matMenu" [overlapTrigger]="false"></mat-menu>

I don't think it is possible to have two in one component but I hope this helps.

This issue is related to the element referencing in angular, so you cannot directly use the multiple mat-menu in a single component.

The trick to do is to create a separate component that implements the mat-menu: Eg,

mat-menu.component.html:

`<div>
    <span>
        <a (click)="openSelectMenu()">Menu
        <mat-icon>arrow_drop_down</mat-icon>
        <div #menuTrigger="matMenuTrigger" [matMenuTriggerFor]="menu1"></div>
        </a>
        <mat-menu #menu1="matMenu" overlapTrigger="false">
        <a mat-menu-item *ngFor="let menu of menuItems">{{menu}}</a></mat-menu>
    </span>
</div>`

mat-menu.component.ts

`@ViewChild(MatMenuTrigger) trigger: MatMenuTrigger;`
`menuItems=['1', '2', '3'];`

 `openSelectMenu() {
    this.trigger.openMenu();
 }`

Now you can use this component multiple times in any component. Eg, app.component.html

`<app-menu></app-menu>
<app-menu></app-menu>`

It will work.

<ul class="navbar-nav ml-auto">
  <li class="nav-item dropdown">
      <button mat-button [matMenuTriggerFor]="admin">ADMIN</button>
      <mat-menu #admin="matMenu">
        <button mat-menu-item>User Management</button>
      </mat-menu>
  </li>
  <li class="nav-item dropdown">
      <button mat-button [matMenuTriggerFor]="profile">PROFILE</button>
      <mat-menu #profile="matMenu">
        <button mat-menu-item>Change Password</button>
        <button mat-menu-item>Logout</button>
      </mat-menu>
  </li>

I had the same issue and I solved it by using the read metadata property of @ViewChild decorator

mainmenu.component.html

<button #menuBtn1 [matMenuTriggerFor]="menu1">Trigger1</button>
<button #menuBtn2 [matMenuTriggerFor]="menu2">Trigger2</button>

mainmenu.component.ts

@ViewChild('menuBtn1', { read: MatMenuTrigger, static: false}) menu1: MatMenuTrigger;
@ViewChild('menuBtn2', { read: MatMenuTrigger, static: false}) menu2: MatMenuTrigger;

foo() {
    this.menu1.openMenu(); // also closeMenu()
    this.menu2.openMenu();
}

The trick is to use the template reference menuBtn1 or menuBtn2 and specify through the read property what you want to get that is the MatMenuTrigger directive

NOTE: I saw that the question refers to angular and angular-material 5. I tested it with angular 8 but it should be the same

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM