1
votes

I have a parent wrapper class and child angular material menu button. When I hover outside of the parent class, I need to hide the whole wrapper. But when I click on the button (which opens mat-menu) which is inside the parent wrapper class, the whole parent closes.

I should be able to do any click operation inside the parent wrapper and only when I hover outside of the parent it should close. How can I implement this?

I've tried adding

event.stopImmediatePropagation();
event.preventDefault();
event.stopPropagation();

on the button click of the child mat menu but still the parent wrapper is getting closed

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

This is the stackblitz link where I reproduced my issue. On click of menu button it should open the menu instead of closing the whole parent div.

I should be able to click on the button menu and should be able to click on the items in the menu

<button mat-button (mouseover)="showBase=true">Hover on me </button>
<div *ngIf="showBase" class="div-style">
   <span  (mouseleave)="showBase=false">
      <button mat-icon-button [matMenuTriggerFor]="menu" 
      #menuTrigger="matMenuTrigger" >
      <mat-icon>menu</mat-icon>
      </button>
      <mat-menu #menu="matMenu" [overlapTrigger]="false">
      <span>
         <button mat-menu-item>
            <mat-icon>home</mat-icon>
            <span>Home</span>
         </button>
         <button mat-menu-item>
            <mat-icon>people_outline</mat-icon>
            <span>Connecting</span>
         </button>
      </span>
      </mat-menu>
   </span>
</div>
2

2 Answers

1
votes

So, the reason it is closing is because when you click on the button to open the menu Angular adds some markup (one being an overlay of the whole screen) which is now under your mouse - so you've effectively triggered a mouseleave or mouseout. As such, you will have to make some changes. But you have options!

  • I'm not sure which version you're using but there is hasBackdrop which could be set to false and may avoid this issue altogether.
  • You can trigger the parent menu open/close via clicks instead of mouse movement. This is the easiest fix but obviously probably not the effect you're going for.
  • Use a second variable to track if the menu is opened or not and keep the parent open if the menu is opened as well. The downside to this is that when the menu closes, so will your parent. Changes to your Stackblitz would look like:

app.component.ts

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

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

app.component.html

<mat-toolbar color="primary">
    <span class="fill-remaining-space">
    <button mat-button (mouseover)="showBase=true">Hover on me </button>
    <div *ngIf="showBase||menuUp" class="div-style" (mouseleave)="showBase=false">
     <span> 
       <button mat-icon-button 
       [matMenuTriggerFor]="menu" 
       #menuTrigger="matMenuTrigger"
       (menuOpened)="menuUp=true"
       (menuClosed)="menuUp=false">
      <mat-icon>menu</mat-icon>
    </button>
    <mat-menu #menu="matMenu" [overlapTrigger]="false">
    <span >
      <button mat-menu-item>
        <mat-icon>home</mat-icon>
        <span>Home</span>
      </button>
      <button mat-menu-item>
        <mat-icon>people_outline</mat-icon>
        <span>Connecting</span>
      </button>
      <button mat-menu-item>
        <mat-icon>videocam</mat-icon>
        <span>Let's talk</span>
      </button>
      <button mat-menu-item>
        <mat-icon>exit_to_app</mat-icon>
        <span>Logout</span>
      </button>
    </span>
</mat-menu></span>
</div>

 </span> 
  <span class="fill-remaining-space">Application Title</span>
</mat-toolbar>

You could work around this issue by thinking about when to set menuUp=false (instead of just on menu close) and adding logic that makes sense for your situation.

1
votes

I modified the above response. I don't want the base container to close even when the inner menu is closed. So I added a overlay container below that and whenever it enters the overlay container , i'm closing the base container.

This is the updated link https://stackblitz.com/edit/angular-yx376k

<mat-toolbar color="primary">
    <span class="fill-remaining-space">
    <button mat-button (mouseover)="showBase=true">Hover on me </button>
    <div class="overlay" style="" (mouseover)="showBase=false;menuUp=false"></div>
    <div *ngIf="showBase||menuUp" class="div-style" (mouseleave)="showBase=false">
     <span> 
       <button mat-icon-button 
       [matMenuTriggerFor]="menu" 
       #menuTrigger="matMenuTrigger"
       (menuOpened)="menuUp=true"
      >
      <mat-icon>menu</mat-icon>
    </button>
    <mat-menu #menu="matMenu" [overlapTrigger]="false">
    <span >
      <button mat-menu-item>
        <mat-icon>home</mat-icon>
        <span>Home</span>
      </button>
      <button mat-menu-item>
        <mat-icon>people_outline</mat-icon>
        <span>Connecting</span>
      </button>
      <button mat-menu-item>
        <mat-icon>videocam</mat-icon>
        <span>Let's talk</span>
      </button>
      <button mat-menu-item>
        <mat-icon>exit_to_app</mat-icon>
        <span>Logout</span>
      </button>
    </span>
</mat-menu></span>
</div>

 </span> 
  <span class="fill-remaining-space">Application Title</span>
</mat-toolbar>