Skip to content

Commit 3d7bed5

Browse files
committed
fix(cdk/overlay): Remove use of zone onStable to detach content
1 parent 3fa56df commit 3d7bed5

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

src/cdk/overlay/overlay-ref.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import {
1414
EnvironmentInjector,
1515
NgZone,
1616
afterNextRender,
17+
afterRender,
18+
untracked,
19+
AfterRenderRef,
1720
} from '@angular/core';
1821
import {Location} from '@angular/common';
1922
import {Observable, Subject, merge, SubscriptionLike, Subscription} from 'rxjs';
@@ -60,6 +63,10 @@ export class OverlayRef implements PortalOutlet {
6063
/** Stream of mouse outside events dispatched to this overlay. */
6164
readonly _outsidePointerEvents = new Subject<MouseEvent>();
6265

66+
private _renders = new Subject<void>();
67+
68+
private _afterRenderRef: AfterRenderRef;
69+
6370
constructor(
6471
private _portalOutlet: PortalOutlet,
6572
private _host: HTMLElement,
@@ -79,6 +86,15 @@ export class OverlayRef implements PortalOutlet {
7986
}
8087

8188
this._positionStrategy = _config.positionStrategy;
89+
90+
this._afterRenderRef = untracked(() =>
91+
afterRender(
92+
() => {
93+
this._renders.next();
94+
},
95+
{injector: this._injector},
96+
),
97+
);
8298
}
8399

84100
/** The overlay's HTML element */
@@ -223,7 +239,7 @@ export class OverlayRef implements PortalOutlet {
223239

224240
// Keeping the host element in the DOM can cause scroll jank, because it still gets
225241
// rendered, even though it's transparent and unclickable which is why we remove it.
226-
this._detachContentWhenStable();
242+
this._detachContentWhenEmpty();
227243
this._locationChanges.unsubscribe();
228244
this._outsideClickDispatcher.remove(this);
229245
return detachmentResult;
@@ -256,6 +272,8 @@ export class OverlayRef implements PortalOutlet {
256272
}
257273

258274
this._detachments.complete();
275+
this._afterRenderRef.destroy();
276+
this._renders.complete();
259277
}
260278

261279
/** Whether the overlay has attached content. */
@@ -491,15 +509,15 @@ export class OverlayRef implements PortalOutlet {
491509
}
492510

493511
/** Detaches the overlay content next time the zone stabilizes. */
494-
private _detachContentWhenStable() {
512+
private _detachContentWhenEmpty() {
495513
// Normally we wouldn't have to explicitly run this outside the `NgZone`, however
496514
// if the consumer is using `zone-patch-rxjs`, the `Subscription.unsubscribe` call will
497515
// be patched to run inside the zone, which will throw us into an infinite loop.
498516
this._ngZone.runOutsideAngular(() => {
499517
// We can't remove the host here immediately, because the overlay pane's content
500518
// might still be animating. This stream helps us avoid interrupting the animation
501519
// by waiting for the pane to become empty.
502-
const subscription = this._ngZone.onStable
520+
const subscription = this._renders
503521
.pipe(takeUntil(merge(this._attachments, this._detachments)))
504522
.subscribe(() => {
505523
// Needs a couple of checks for the pane and host, because

0 commit comments

Comments
 (0)