mat-menu scrolls down with the page on fixed bottom nav, only mobile&chrome

Viewed 2004

dependencies: @angular/material 6.4.7, @angular/cdk 6.4.7

Issue: https://github.com/angular/material2/issues/11365

They say it's fixed but Im still getting the following behaviour, ONLY ON MOBILE & CHROME

enter image description here

NOTE: The Pikachu Button that appears when scrolling it doesnt affect anything, Tested.

<button class="nav-Menu" mat-icon-button [matMenuTriggerFor]="menu">
 <mat-icon>more_vert</mat-icon>
</button>

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

<button [routerLink]="['home']" routerLinkActive="active" mat-menu-item>
  <mat-icon svgIcon="pikachu"></mat-icon> <!-- Home -->
  <span>Home</span>
</button>

<button routerLinkActive="active" mat-menu-item 
 [matMenuTriggerFor]="Database">
  <mat-icon svgIcon="database"></mat-icon> <!-- Database -->
  <span>Database</span>
</button>

<button routerLinkActive="active" mat-menu-item [matMenuTriggerFor]="Tools">
 <mat-icon svgIcon="tools"></mat-icon> <!-- Tools -->
 <span>Tools</span>
</button>

<button routerLinkActive="active" mat-menu-item 
[matMenuTriggerFor]="Guides">
  <mat-icon svgIcon="guides"></mat-icon> <!-- Guides -->
  <span>Guides</span>
</button>

</mat-menu>

<mat-menu #Database="matMenu" > <!-- Database Menu -->
  <button [routerLink]="['pokedex']" routerLinkActive="active"
      mat-menu-item><mat-icon svgIcon="bulbasaur"></mat-icon>Pokédex
  </button>
  <button [routerLink]="['moves']" routerLinkActive="active"
      mat-menu-item><mat-icon svgIcon="move"></mat-icon>Moves
  </button>
</mat-menu>

<mat-menu #Tools="matMenu" > <!-- Tools Menu -->
  <button [routerLink]="['laboratory']" routerLinkActive="active"
      mat-menu-item><mat-icon svgIcon="laboratory"></mat-icon>Laboratory
  </button>
</mat-menu>

<mat-menu #Guides="matMenu"> <!-- Guides Menu -->
  <button [routerLink]="['guides/victory-road']" routerLinkActive="active"
      mat-menu-item><mat-icon svgIcon="victory-road"></mat-icon>Victory Road
  </button>
</mat-menu>

NOTE 2: Top nav mat-menu is working as expected, Issue only on bottom fixed nav

1 Answers

Well, I don't know if it helps, but most of "popup" components in angular material have some things in common, like backdrops and panelClass, as well as a ScrollStrategy, which defines how those components should behave. There are 4 types, "reposition", "noop", "close" and "block". "reposition" is the default, and changes mat-menu position as you scroll... "noop" means its gonna stay in the same position whether the page is scrolled or not, "close" means that mat-menu will close whenever you start to scroll OUTSIDE the mat-menu... finally "block" means that you CANNOT scroll OUTSIDE the mat-menu. Here is an example of how I conditionally implement it depending on the user's device, whether is touchable or not:


import { MAT_MENU_SCROLL_STRATEGY } from '@angular/material';
import { Overlay, BlockScrollStrategy, RepositionScrollStrategy, CloseScrollStrategy, NoopScrollStrategy } from '@angular/cdk/overlay';


const isToucheDevice = () => {
  try {
    document.createEvent('TouchEvent');
    return true;
  } catch (e) {
    return false;
  }
};

const scrollBlockFactory = (overlay: Overlay): () => BlockScrollStrategy  => {
  return () => overlay.scrollStrategies.block();
};

const scrollRepositionFactory = (overlay: Overlay): () => RepositionScrollStrategy  => {
  return () => overlay.scrollStrategies.reposition();
};

@Component({
  selector: 'app-search-criteria-form',
  templateUrl: './search-criteria-form.component.html',
  styleUrls: ['./search-criteria-form.component.scss'],
  providers: [
    { provide: MAT_MENU_SCROLL_STRATEGY, useFactory: isToucheDevice() ? scrollBlockFactory : scrollRepositionFactory, deps: [Overlay] }
  ]
})


Is important that you add it on the component's provider, and, BTW, it has to be in the parent component, or at least I could not make it work at the same level where I was using the mat-menu... Is also important that whenever you are making the functions you checkout you are passing the type, defining whether it should return a RepositionScrollStrategy or whichever. Like this (obviously without the stars):

const scrollRepositionFactory = (overlay: Overlay): () => **RepositionScrollStrategy**  => {
  return () => overlay.scrollStrategies.reposition();
};
Related