Skip to content

Commit 0a00229

Browse files
committed
fix(overlay): clear timeout if the backdrop transition completes early
Currently we have a `setTimeout` as a fallback for the backdrop animation not completing. These changes clear the timeout if the animation finished first so we don't have to do extra work.
1 parent c276e26 commit 0a00229

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

src/cdk/overlay/overlay-ref.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export class OverlayRef implements PortalOutlet {
331331
let backdropToDetach = this._backdropElement;
332332

333333
if (backdropToDetach) {
334+
let timeoutId: number;
334335
let finishDetach = () => {
335336
// It may not be attached to anything in certain cases (e.g. unit tests).
336337
if (backdropToDetach && backdropToDetach.parentNode) {
@@ -343,6 +344,8 @@ export class OverlayRef implements PortalOutlet {
343344
if (this._backdropElement == backdropToDetach) {
344345
this._backdropElement = null;
345346
}
347+
348+
clearTimeout(timeoutId);
346349
};
347350

348351
backdropToDetach.classList.remove('cdk-overlay-backdrop-showing');
@@ -360,7 +363,7 @@ export class OverlayRef implements PortalOutlet {
360363
// Run this outside the Angular zone because there's nothing that Angular cares about.
361364
// If it were to run inside the Angular zone, every test that used Overlay would have to be
362365
// either async or fakeAsync.
363-
this._ngZone.runOutsideAngular(() => setTimeout(finishDetach, 500));
366+
timeoutId = this._ngZone.runOutsideAngular(() => setTimeout(finishDetach, 500));
364367
}
365368
}
366369

src/cdk/overlay/overlay.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
EventEmitter,
1010
} from '@angular/core';
1111
import {Direction, Directionality} from '@angular/cdk/bidi';
12+
import {dispatchFakeEvent} from '@angular/cdk/testing';
1213
import {
1314
ComponentPortal,
1415
PortalModule,
@@ -292,6 +293,19 @@ describe('Overlay', () => {
292293
expect(overlayRef.backdropElement).toBeFalsy('Expected backdrop element not to be referenced.');
293294
}));
294295

296+
it('should clear the backdrop timeout if the transition finishes first', fakeAsync(() => {
297+
const overlayRef = overlay.create({hasBackdrop: true});
298+
299+
overlayRef.attach(componentPortal);
300+
overlayRef.detach();
301+
302+
const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop')!;
303+
dispatchFakeEvent(backdrop, 'transitionend');
304+
305+
// Note: we don't `tick` or `flush` here. The assertion is that
306+
// `fakeAsync` will throw if we have an unflushed timer.
307+
}));
308+
295309
it('should be able to use the `Overlay` provider during app initialization', () => {
296310
/** Dummy provider that depends on `Overlay`. */
297311
@Injectable()

0 commit comments

Comments
 (0)