Components: Recalculate position of mat-menu on height change

Created on 23 Oct 2019  路  5Comments  路  Source: angular/components

What are you trying to do?

A way to recalculate the position of a mat-menu panel if it changes its height after opened. I don't need to do it automatically, I'm just seeking a way to ask mat-menu to recalculate the position.

What troubleshooting steps have you tried?

Wasn't able to achieve it without dirty tricks (for example triggering a window resize event). Asked in StackOverflow with no luck: https://stackoverflow.com/questions/58375853/angular-material-recalculate-position-of-mat-menu-on-height-change

Reproduction

Steps to reproduce:

  1. Go to https://stackblitz.com/edit/angular-lorwfh?file=app/menu-overview-example.ts
  2. Open the mat-menu and wait for a second. It will be displayed incorrectly until you either resize the window or close&open the panel.

Environment

  • Angular: 8.2.10
  • CDK/Material: 8.2.1
  • Browser(s): all (tested in Firefox & Chrome)
  • Operating System (e.g. Windows, macOS, Ubuntu): all (tested in macOS & Debian)
P4 materiamenu feature

All 5 comments

I don't think it's a good user experience if suddenly the menu changes it's size and position. I would hate it.

@manklu What'd you do then if you need to load data to populate the panel? We change its height because we show a spinner while loading it.

I would show a spinner (if the data is loaded via network) and delay the display of the menu until the data has been loaded.

We should be able to expose a method that tells the menu to reposition itself.

Made a global search for the resize event handlers, and found one of them in flexible-connected-position-strategy.ts, which should be the default position strategy with mat-menu.

https://github.com/angular/components/blob/8.2.3/src/cdk/overlay/position/flexible-connected-position-strategy.ts#L160-L166

We could manually run the code block inside the resize event handler. However, the code mostly touches on the private properties, and hence we will need to forcibly bypass the TypeScript checking with as any.

function recalculateMenu(menuTrigger: MatMenuTrigger) {
  // get the OverlayRef from MatMenuTrigger
  const overlayRef: OverlayRef = (menuTrigger as any)._overlayRef;

  // get the FlexibleConnectedPositionStrategy from OverlayRef
  const overlayConfig = overlayRef.getConfig();

  // repeat what was done in the resize event handler
  (overlayConfig.positionStrategy as any)._isInitialRender = true;
  overlayConfig.positionStrategy.apply();
}

And with that in mind, here is the revised StackBlitz.
https://stackblitz.com/edit/angular-lorwfh-sfgdnm?file=app%2Fmenu-overview-example.ts

I would consider this a dirty trick as well, but at least it is a temporary solution.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

savaryt picture savaryt  路  3Comments

3mp3ri0r picture 3mp3ri0r  路  3Comments

crutchcorn picture crutchcorn  路  3Comments

xtianus79 picture xtianus79  路  3Comments

theunreal picture theunreal  路  3Comments