0

I got menu that is being displayed on mouseenter event of a button. All that in toolbar:

<mat-toolbar color="primary">
  <button mat-button routerLink="/products" [matMenuTriggerFor]="menu1"
      #matMenu1Trigger="matMenuTrigger"
      (mouseenter)="matMenu1Trigger.openMenu()">Menu1
  </button>
  <mat-menu #menu1="matMenu">
    <div (mouseleave)="matMenu1Trigger.closeMenu()">
      <button mat-menu-item>Item 1</button>
    </div>
  </mat-menu>
</mat-toolbar>

The menu is closed when mouseleave event of surrounding span, so far so good. Now I want to close the menu on mouseleave of the triggering button as well by adding

(mouseleave)="matMenu1Trigger.closeMenu()"

When I do this and move mouse over this button, menu starts to flicker, like its being opened/closed every few miliseconds.

Why is that and how to hide the menu when mouse leaves the button?

https://stackblitz.com/edit/angular-kd8bue

Edit: After some googling I found out this behavior is caused by an overlay being displayed when the menu is opened as described here How to open mat-menu on a single click and close other opened menu if there is any?. Not sure if what I would like to achieve is even possible because of the overlay...

user1622058
  • 453
  • 3
  • 7
  • 16
  • Do you want to try this with `css` instead of `javascript`? – Mohi Nov 21 '18 at 09:46
  • Try to bind menu's `opened` value to a component typescript variable instead and to change that value from the event.. Like: (HTML) `` (TYPESCRIPT): `var varOpened: boolean = false;` (HTML): `
    ` (TYPESCRIPT):`closeMenu(){ this.varOpened=false; }`. I don't have tested but I always acted like this way before with Angular Material's stuff so... let me know if it works!
    – Deadpool Nov 21 '18 at 09:52
  • @Deadpool: There is no such property as `opened`, see https://material.angular.io/components/menu/api – user1622058 Nov 21 '18 at 15:54

2 Answers2

2

Please review this closed issue on github

https://github.com/angular/material2/issues/10378#issuecomment-372626596

When your mouseenter opens the mat-menu... a cdkOverlay is created and focus set to the mat-menu cdkOverlay, this immediately fires your mouseleave event because the focus is now on the overlay and not your button... even though your mouse is still over the button.


Revision

Please review the below stackblitz I did for this SO answer.

How to open and close Angular mat menu on hover

https://stackblitz.com/edit/mat-nested-menu-yclrmd?embed=1&file=app/nested-menu-example.html

Marshal
  • 10,499
  • 2
  • 34
  • 53
  • Thanks for explanation, that's what I was looking for, understand why is this happening. The workaround, yeah, not really but thanks anyway. – user1622058 Nov 22 '18 at 10:06
  • great job! It's just pity that such an elementary functionality isn't build in. Maybe using third-party component? – user1622058 Dec 05 '18 at 21:09
  • When you try to use the menu scrollbar with the mouse the menu disappears. Does anybody know how to prevent this from happening? @Marshal – Bazoozoos Apr 21 '23 at 11:33
1
    <mat-toolbar color="primary">
        <button   mat-button >Menu0 </button>

        <button mat-button routerLink="/products" [matMenuTriggerFor]="menu1"
        #matMenu1Trigger="matMenuTrigger"
        (mouseenter)="buttonenter()"
        (mouseout)="buttonleave()" style=" z-index: 50000">Menu1
        </button>
        <mat-menu #menu1="matMenu" >
          <div (mouseleave)="matMenu1Trigger.closeMenu()"
          (mouseenter)="menuenter()"
          >
        <button mat-menu-item>Item 1</button>
        <button mat-menu-item>Item 2</button>
        <button mat-menu-item>Item 3</button>
        <button mat-menu-item>Item 4</button>
        <button mat-menu-item>Item 5</button>
        <button mat-menu-item>Item 6</button>        
          </div>
        </mat-menu>

          <button   mat-button >MenuX </button>


          <button mat-button routerLink="/products" [matMenuTriggerFor]="menu2"
        #matMenu1Trigger2="matMenuTrigger"
        (mouseenter)="buttonenter2()"
        (mouseout)="buttonleave2()" style=" z-index: 50000">Menu2
        </button>
        <mat-menu #menu2="matMenu" >
          <div (mouseleave)="matMenu1Trigger2.closeMenu()"
           (mouseenter)="menuenter2()"
          >
        <button mat-menu-item>Item2 1</button>
        <button mat-menu-item>Item2 2</button>
        <button mat-menu-item>Item2 3</button>
        <button mat-menu-item>Item2 4</button>
        <button mat-menu-item>Item2 5</button>
        <button mat-menu-item>Item2 6</button>          

          </div>
        </mat-menu>

          <button   mat-button >Menu3 </button>
          <button   mat-button >Menu4 </button>
          <button   mat-button >Menu5 </button>
          <button   mat-button >Menu6 </button>


      </mat-toolbar>


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

    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {

      name = 'Angular';
      isEnterMatMenuOpen = false;
      @ViewChild('matMenu1Trigger') _matMenu1Trigger
      @ViewChild('menuButton') _menuButton

      isEnterMatMenuOpen2 = false;
      @ViewChild('matMenu1Trigger2') _matMenu1Trigger2
      @ViewChild('menuButton2') _menuButton2

      buttonenter() {
          this._matMenu1Trigger.openMenu();
          this.isEnterMatMenuOpen = false;
      }
      menuenter() {
          this.isEnterMatMenuOpen = true;
      }
      buttonleave() {
        setTimeout(() => {
        if( !this.isEnterMatMenuOpen ) this._matMenu1Trigger.closeMenu();
        }, 50);
      }

      buttonenter2() {
           this._matMenu1Trigger2.openMenu();  
          this.isEnterMatMenuOpen2 = false; 
      }
      menuenter2() {
          this.isEnterMatMenuOpen2 = true;
      }
      buttonleave2() {
        setTimeout(() => {
        if( !this.isEnterMatMenuOpen2 ) this._matMenu1Trigger2.closeMenu();
        }, 50);
      } 

    }
Jimmy
  • 11
  • 2
  • 1
    The above code will work to hover and leave angular material menu items. The key is: style=" z-index: 50000" to make it works. It is a rough test code for the concept. You have to make the code looks nice if you want to use it. – Jimmy Nov 22 '18 at 06:31
  • This looks nice but only on first look. On second, sometimes its impossible to mouse into the menu because the menu closes. Also when I move the pointer from button to newly opened menu and try to move back to button, second menu duplicate pops-up right next to the opened one. Didn't expect having such an menu would be such an issue with Angular Material... Especially compared to competition like https://mdbootstrap.com, https://www.primefaces.org/primeng/#/ etc – user1622058 Nov 22 '18 at 10:11