Skip to content

Commit 1e1751f

Browse files
crisbetojelbourn
authored andcommitted
fix(menu): menu content data being cleared when lazy-loaded content is reused between nested triggers (#12476)
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.
1 parent ef57919 commit 1e1751f

File tree

2 files changed

+13
-3
lines changed

2 files changed

+13
-3
lines changed

src/lib/menu/menu-content.ts

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from '@angular/core';
1919
import {TemplatePortal, DomPortalOutlet} from '@angular/cdk/portal';
2020
import {DOCUMENT} from '@angular/common';
21+
import {Subject} from 'rxjs';
2122

2223
/**
2324
* Menu content that will be rendered lazily once the menu is opened.
@@ -29,6 +30,9 @@ export class MatMenuContent implements OnDestroy {
2930
private _portal: TemplatePortal<any>;
3031
private _outlet: DomPortalOutlet;
3132

33+
/** Emits when the menu content has been attached. */
34+
_attached = new Subject<void>();
35+
3236
constructor(
3337
private _template: TemplateRef<any>,
3438
private _componentFactoryResolver: ComponentFactoryResolver,
@@ -60,6 +64,7 @@ export class MatMenuContent implements OnDestroy {
6064
// risk it staying attached to a pane that's no longer in the DOM.
6165
element.parentNode!.insertBefore(this._outlet.outletElement, element);
6266
this._portal.attach(this._outlet, context);
67+
this._attached.next();
6368
}
6469

6570
/**

src/lib/menu/menu-trigger.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,14 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
245245
if (menu.lazyContent) {
246246
// Wait for the exit animation to finish before detaching the content.
247247
menu._animationDone
248-
.pipe(filter(event => event.toState === 'void'), take(1))
249-
.subscribe(() => {
250-
menu.lazyContent!.detach();
248+
.pipe(
249+
filter(event => event.toState === 'void'),
250+
take(1),
251+
// Interrupt if the content got re-attached.
252+
takeUntil(menu.lazyContent._attached)
253+
)
254+
.subscribe(() => menu.lazyContent!.detach(), undefined, () => {
255+
// No matter whether the content got re-attached, reset the menu.
251256
this._resetMenu();
252257
});
253258
} else {

0 commit comments

Comments
 (0)