@@ -186,25 +186,9 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
186186 // Remove this overlay from keyboard dispatcher tracking.
187187 this . _keyboardDispatcher . remove ( this ) ;
188188
189- // Keeping the host element in DOM the can cause scroll jank, because it still gets rendered,
190- // even though it's transparent and unclickable. We can't remove the host here immediately,
191- // because the overlay pane's content might still be animating. This stream helps us avoid
192- // interrupting the animation by waiting for the pane to become empty.
193- const subscription = this . _ngZone . onStable
194- . asObservable ( )
195- . pipe ( takeUntil ( merge ( this . _attachments , this . _detachments ) ) )
196- . subscribe ( ( ) => {
197- // Needs a couple of checks for the pane and host, because
198- // they may have been removed by the time the zone stabilizes.
199- if ( ! this . _pane || ! this . _host || this . _pane . children . length === 0 ) {
200- if ( this . _host && this . _host . parentElement ) {
201- this . _previousHostParent = this . _host . parentElement ;
202- this . _previousHostParent . removeChild ( this . _host ) ;
203- }
204-
205- subscription . unsubscribe ( ) ;
206- }
207- } ) ;
189+ // Keeping the host element in DOM the can cause scroll jank, because it still gets
190+ // rendered, even though it's transparent and unclickable which is why we remove it.
191+ this . _detachContentWhenStable ( ) ;
208192
209193 return detachmentResult ;
210194 }
@@ -425,6 +409,33 @@ export class OverlayRef implements PortalOutlet, OverlayReference {
425409 isAdd ? classList . add ( cssClass ) : classList . remove ( cssClass ) ;
426410 } ) ;
427411 }
412+
413+ /** Detaches the overlay content next time the zone stabilizes. */
414+ private _detachContentWhenStable ( ) {
415+ // Normally we wouldn't have to explicitly run this outside the `NgZone`, however
416+ // if the consumer is using `zone-patch-rxjs`, the `Subscription.unsubscribe` call will
417+ // be patched to run inside the zone, which will throw us into an infinite loop.
418+ this . _ngZone . runOutsideAngular ( ( ) => {
419+ // We can't remove the host here immediately, because the overlay pane's content
420+ // might still be animating. This stream helps us avoid interrupting the animation
421+ // by waiting for the pane to become empty.
422+ const subscription = this . _ngZone . onStable
423+ . asObservable ( )
424+ . pipe ( takeUntil ( merge ( this . _attachments , this . _detachments ) ) )
425+ . subscribe ( ( ) => {
426+ // Needs a couple of checks for the pane and host, because
427+ // they may have been removed by the time the zone stabilizes.
428+ if ( ! this . _pane || ! this . _host || this . _pane . children . length === 0 ) {
429+ if ( this . _host && this . _host . parentElement ) {
430+ this . _previousHostParent = this . _host . parentElement ;
431+ this . _previousHostParent . removeChild ( this . _host ) ;
432+ }
433+
434+ subscription . unsubscribe ( ) ;
435+ }
436+ } ) ;
437+ } ) ;
438+ }
428439}
429440
430441
0 commit comments