Skip to content

Commit e98372e

Browse files
crisbetoandrewseguin
authored andcommitted
fix(overlay): emit attach and detach at appropriate times (#4880)
* Emits the `attachments` when everything has been attached. * Emits the `detachments` when everything has been detached. * Completes the `attachments` observable before the `detachments`. Fixes #4871.
1 parent c8b1e20 commit e98372e

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

src/lib/core/overlay/overlay-ref.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export class OverlayRef implements PortalHost {
4444
this.updateSize();
4545
this.updateDirection();
4646
this.updatePosition();
47-
this._attachments.next();
4847
this._scrollStrategy.enable();
4948

5049
// Enable pointer events for the overlay pane element.
@@ -58,6 +57,9 @@ export class OverlayRef implements PortalHost {
5857
this._pane.classList.add(this._state.panelClass);
5958
}
6059

60+
// Only emit the `attachments` event once all other setup is done.
61+
this._attachments.next();
62+
6163
return attachResult;
6264
}
6365

@@ -73,9 +75,13 @@ export class OverlayRef implements PortalHost {
7375
// pointer events therefore. Depends on the position strategy and the applied pane boundaries.
7476
this._togglePointerEvents(false);
7577
this._scrollStrategy.disable();
78+
79+
let detachmentResult = this._portalHost.detach();
80+
81+
// Only emit after everything is detached.
7682
this._detachments.next();
7783

78-
return this._portalHost.detach();
84+
return detachmentResult;
7985
}
8086

8187
/**
@@ -93,9 +99,9 @@ export class OverlayRef implements PortalHost {
9399

94100
this.detachBackdrop();
95101
this._portalHost.dispose();
102+
this._attachments.complete();
96103
this._detachments.next();
97104
this._detachments.complete();
98-
this._attachments.complete();
99105
}
100106

101107
/**

src/lib/core/overlay/overlay.spec.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,24 @@ describe('Overlay', () => {
147147
expect(spy).toHaveBeenCalled();
148148
});
149149

150+
it('should emit the attachment event after everything is added to the DOM', () => {
151+
let state = new OverlayState();
152+
153+
state.hasBackdrop = true;
154+
155+
let overlayRef = overlay.create(state);
156+
157+
overlayRef.attachments().subscribe(() => {
158+
expect(overlayContainerElement.querySelector('pizza'))
159+
.toBeTruthy('Expected the overlay to have been attached.');
160+
161+
expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop'))
162+
.toBeTruthy('Expected the backdrop to have been attached.');
163+
});
164+
165+
overlayRef.attach(componentPortal);
166+
});
167+
150168
it('should emit when an overlay is detached', () => {
151169
let overlayRef = overlay.create();
152170
let spy = jasmine.createSpy('detachments spy');
@@ -158,6 +176,18 @@ describe('Overlay', () => {
158176
expect(spy).toHaveBeenCalled();
159177
});
160178

179+
it('should emit the detachment event after the overlay is removed from the DOM', () => {
180+
let overlayRef = overlay.create();
181+
182+
overlayRef.detachments().subscribe(() => {
183+
expect(overlayContainerElement.querySelector('pizza'))
184+
.toBeFalsy('Expected the overlay to have been detached.');
185+
});
186+
187+
overlayRef.attach(componentPortal);
188+
overlayRef.detach();
189+
});
190+
161191
it('should emit and complete the observables when an overlay is disposed', () => {
162192
let overlayRef = overlay.create();
163193
let disposeSpy = jasmine.createSpy('dispose spy');
@@ -175,6 +205,19 @@ describe('Overlay', () => {
175205
expect(detachCompleteSpy).toHaveBeenCalled();
176206
});
177207

208+
it('should complete the attachment observable before the detachment one', () => {
209+
let overlayRef = overlay.create();
210+
let callbackOrder = [];
211+
212+
overlayRef.attachments().subscribe(null, null, () => callbackOrder.push('attach'));
213+
overlayRef.detachments().subscribe(null, null, () => callbackOrder.push('detach'));
214+
215+
overlayRef.attach(componentPortal);
216+
overlayRef.dispose();
217+
218+
expect(callbackOrder).toEqual(['attach', 'detach']);
219+
});
220+
178221
describe('positioning', () => {
179222
let state: OverlayState;
180223

@@ -421,7 +464,10 @@ describe('OverlayContainer theming', () => {
421464
});
422465

423466
/** Simple component for testing ComponentPortal. */
424-
@Component({template: '<p>Pizza</p>'})
467+
@Component({
468+
selector: 'pizza',
469+
template: '<p>Pizza</p>'
470+
})
425471
class PizzaMsg { }
426472

427473

0 commit comments

Comments
 (0)