angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.36k stars 6.74k forks source link

Recalculate position of mat-menu on height change #17477

Open acalvo opened 5 years ago

acalvo commented 5 years ago

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

manklu commented 5 years ago

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

acalvo commented 5 years ago

@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.

manklu commented 5 years ago

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.

crisbeto commented 4 years ago

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

altbdoor commented 4 years ago

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.

angular-robot[bot] commented 2 years ago

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

angular-robot[bot] commented 2 years ago

Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

You can find more details about the feature request process in our documentation.