@@ -40,7 +40,7 @@ import {
4040} from '@angular/core' ;
4141import { normalizePassiveListenerOptions } from '@angular/cdk/platform' ;
4242import { merge , Observable , of as observableOf , Subscription } from 'rxjs' ;
43- import { filter , take , takeUntil } from 'rxjs/operators' ;
43+ import { filter , takeUntil } from 'rxjs/operators' ;
4444import { MatMenu , MenuCloseReason } from './menu' ;
4545import { throwMatMenuRecursiveError } from './menu-errors' ;
4646import { MatMenuItem } from './menu-item' ;
@@ -115,7 +115,6 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
115115 private _closingActionsSubscription = Subscription . EMPTY ;
116116 private _hoverSubscription = Subscription . EMPTY ;
117117 private _menuCloseSubscription = Subscription . EMPTY ;
118- private _pendingRemoval : Subscription | undefined ;
119118
120119 /**
121120 * We're specifically looking for a `MatMenu` here since the generic `MatMenuPanel`
@@ -248,7 +247,6 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
248247 passiveEventListenerOptions ,
249248 ) ;
250249
251- this . _pendingRemoval ?. unsubscribe ( ) ;
252250 this . _menuCloseSubscription . unsubscribe ( ) ;
253251 this . _closingActionsSubscription . unsubscribe ( ) ;
254252 this . _hoverSubscription . unsubscribe ( ) ;
@@ -287,39 +285,24 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
287285 return ;
288286 }
289287
290- this . _pendingRemoval ?. unsubscribe ( ) ;
291- const previousTrigger = PANELS_TO_TRIGGERS . get ( menu ) ;
292- PANELS_TO_TRIGGERS . set ( menu , this ) ;
293-
294- // If the same menu is currently attached to another trigger,
295- // we need to close it so it doesn't end up in a broken state.
296- if ( previousTrigger && previousTrigger !== this ) {
297- previousTrigger . closeMenu ( ) ;
298- }
299-
300288 const overlayRef = this . _createOverlay ( menu ) ;
301289 const overlayConfig = overlayRef . getConfig ( ) ;
302290 const positionStrategy = overlayConfig . positionStrategy as FlexibleConnectedPositionStrategy ;
303291
304292 this . _setPosition ( menu , positionStrategy ) ;
305293 overlayConfig . hasBackdrop =
306294 menu . hasBackdrop == null ? ! this . triggersSubmenu ( ) : menu . hasBackdrop ;
295+ overlayRef . attach ( this . _getPortal ( menu ) ) ;
307296
308- // We need the `hasAttached` check for the case where the user kicked off a removal animation,
309- // but re-entered the menu. Re-attaching the same portal will trigger an error otherwise.
310- if ( ! overlayRef . hasAttached ( ) ) {
311- overlayRef . attach ( this . _getPortal ( menu ) ) ;
312- menu . lazyContent ?. attach ( this . menuData ) ;
297+ if ( menu . lazyContent ) {
298+ menu . lazyContent . attach ( this . menuData ) ;
313299 }
314300
315301 this . _closingActionsSubscription = this . _menuClosingActions ( ) . subscribe ( ( ) => this . closeMenu ( ) ) ;
316- menu . parentMenu = this . triggersSubmenu ( ) ? this . _parentMaterialMenu : undefined ;
317- menu . direction = this . dir ;
318- menu . focusFirstItem ( this . _openedBy || 'program' ) ;
319- this . _setIsMenuOpen ( true ) ;
302+ this . _initMenu ( menu ) ;
320303
321304 if ( menu instanceof MatMenu ) {
322- menu . _setIsOpen ( true ) ;
305+ menu . _startAnimation ( ) ;
323306 menu . _directDescendantItems . changes . pipe ( takeUntil ( menu . close ) ) . subscribe ( ( ) => {
324307 // Re-adjust the position without locking when the amount of items
325308 // changes so that the overlay is allowed to pick a new optimal position.
@@ -355,28 +338,12 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
355338
356339 /** Closes the menu and does the necessary cleanup. */
357340 private _destroyMenu ( reason : MenuCloseReason ) {
358- const overlayRef = this . _overlayRef ;
359- const menu = this . _menu ;
360-
361- if ( ! overlayRef || ! this . menuOpen ) {
341+ if ( ! this . _overlayRef || ! this . menuOpen ) {
362342 return ;
363343 }
364344
365345 this . _closingActionsSubscription . unsubscribe ( ) ;
366- this . _pendingRemoval ?. unsubscribe ( ) ;
367-
368- // Note that we don't wait for the animation to finish if another trigger took
369- // over the menu, because the panel will end up empty which looks glitchy.
370- if ( menu instanceof MatMenu && this . _ownsMenu ( menu ) ) {
371- this . _pendingRemoval = menu . _animationDone . pipe ( take ( 1 ) ) . subscribe ( ( ) => overlayRef . detach ( ) ) ;
372- menu . _setIsOpen ( false ) ;
373- } else {
374- overlayRef . detach ( ) ;
375- }
376-
377- if ( menu && this . _ownsMenu ( menu ) ) {
378- PANELS_TO_TRIGGERS . delete ( menu ) ;
379- }
346+ this . _overlayRef . detach ( ) ;
380347
381348 // Always restore focus if the user is navigating using the keyboard or the menu was opened
382349 // programmatically. We don't restore for non-root triggers, because it can prevent focus
@@ -388,6 +355,30 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
388355
389356 this . _openedBy = undefined ;
390357 this . _setIsMenuOpen ( false ) ;
358+
359+ if ( this . menu && this . _ownsMenu ( this . menu ) ) {
360+ PANELS_TO_TRIGGERS . delete ( this . menu ) ;
361+ }
362+ }
363+
364+ /**
365+ * This method sets the menu state to open and focuses the first item if
366+ * the menu was opened via the keyboard.
367+ */
368+ private _initMenu ( menu : MatMenuPanel ) : void {
369+ const previousTrigger = PANELS_TO_TRIGGERS . get ( menu ) ;
370+
371+ // If the same menu is currently attached to another trigger,
372+ // we need to close it so it doesn't end up in a broken state.
373+ if ( previousTrigger && previousTrigger !== this ) {
374+ previousTrigger . closeMenu ( ) ;
375+ }
376+
377+ PANELS_TO_TRIGGERS . set ( menu , this ) ;
378+ menu . parentMenu = this . triggersSubmenu ( ) ? this . _parentMaterialMenu : undefined ;
379+ menu . direction = this . dir ;
380+ menu . focusFirstItem ( this . _openedBy || 'program' ) ;
381+ this . _setIsMenuOpen ( true ) ;
391382 }
392383
393384 // set state rather than toggle to support triggers sharing a menu
0 commit comments