From d67338847d4e21002f5d61364ed04194da39c32e Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 1 Aug 2018 22:51:08 +0200 Subject: [PATCH] fix(menu): menu content data being cleared when lazy-loaded content is reused between nested triggers Fixes an issue where a nested menu with lazy-loaded that is reused between multiple triggers will clear its content once an alternate trigger is hovered. The issue comes from the fact that we wait for the exit animation to finish before we detach the content, which ends up detaching the content of the new trigger as well. Fixes #12467. --- src/lib/menu/menu-content.ts | 5 +++++ src/lib/menu/menu-trigger.ts | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lib/menu/menu-content.ts b/src/lib/menu/menu-content.ts index e8d16b824ea5..2329777becb5 100644 --- a/src/lib/menu/menu-content.ts +++ b/src/lib/menu/menu-content.ts @@ -18,6 +18,7 @@ import { } from '@angular/core'; import {TemplatePortal, DomPortalOutlet} from '@angular/cdk/portal'; import {DOCUMENT} from '@angular/common'; +import {Subject} from 'rxjs'; /** * Menu content that will be rendered lazily once the menu is opened. @@ -29,6 +30,9 @@ export class MatMenuContent implements OnDestroy { private _portal: TemplatePortal; private _outlet: DomPortalOutlet; + /** Emits when the menu content has been attached. */ + _attached = new Subject(); + constructor( private _template: TemplateRef, private _componentFactoryResolver: ComponentFactoryResolver, @@ -60,6 +64,7 @@ export class MatMenuContent implements OnDestroy { // risk it staying attached to a pane that's no longer in the DOM. element.parentNode!.insertBefore(this._outlet.outletElement, element); this._portal.attach(this._outlet, context); + this._attached.next(); } /** diff --git a/src/lib/menu/menu-trigger.ts b/src/lib/menu/menu-trigger.ts index a099665a3b66..b2895608564a 100644 --- a/src/lib/menu/menu-trigger.ts +++ b/src/lib/menu/menu-trigger.ts @@ -245,9 +245,14 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { if (menu.lazyContent) { // Wait for the exit animation to finish before detaching the content. menu._animationDone - .pipe(filter(event => event.toState === 'void'), take(1)) - .subscribe(() => { - menu.lazyContent!.detach(); + .pipe( + filter(event => event.toState === 'void'), + take(1), + // Interrupt if the content got re-attached. + takeUntil(menu.lazyContent._attached) + ) + .subscribe(() => menu.lazyContent!.detach(), undefined, () => { + // No matter whether the content got re-attached, reset the menu. this._resetMenu(); }); } else {