diff --git a/src/lib/core/overlay/overlay-ref.ts b/src/lib/core/overlay/overlay-ref.ts index 0a8e42d2ffda..8da9d5c5dc97 100644 --- a/src/lib/core/overlay/overlay-ref.ts +++ b/src/lib/core/overlay/overlay-ref.ts @@ -30,13 +30,10 @@ export class OverlayRef implements PortalHost { * @returns The portal attachment result. */ attach(portal: Portal): any { - if (this._state.hasBackdrop) { - this._attachBackdrop(); - } - let attachResult = this._portalHost.attach(portal); // Update the pane element with the given state configuration. + this._updateStackingOrder(); this.updateSize(); this.updateDirection(); this.updatePosition(); @@ -44,6 +41,10 @@ export class OverlayRef implements PortalHost { // Enable pointer events for the overlay pane element. this._togglePointerEvents(true); + if (this._state.hasBackdrop) { + this._attachBackdrop(); + } + return attachResult; } @@ -153,6 +154,19 @@ export class OverlayRef implements PortalHost { }); } + /** + * Updates the stacking order of the element, moving it to the top if necessary. + * This is required in cases where one overlay was detached, while another one, + * that should be behind it, was destroyed. The next time both of them are opened, + * the stacking will be wrong, because the detached element's pane will still be + * in its original DOM position. + */ + private _updateStackingOrder() { + if (this._pane.nextSibling) { + this._pane.parentNode.appendChild(this._pane); + } + } + /** Detaches the backdrop (if any) associated with the overlay. */ detachBackdrop(): void { let backdropToDetach = this._backdropElement; diff --git a/src/lib/core/overlay/overlay.spec.ts b/src/lib/core/overlay/overlay.spec.ts index 328809e4d272..348f1cdcb51c 100644 --- a/src/lib/core/overlay/overlay.spec.ts +++ b/src/lib/core/overlay/overlay.spec.ts @@ -100,6 +100,31 @@ describe('Overlay', () => { expect(overlayContainerElement.textContent).toBe(''); }); + it('should ensure that the most-recently-attached overlay is on top', () => { + let pizzaOverlayRef = overlay.create(); + let cakeOverlayRef = overlay.create(); + + pizzaOverlayRef.attach(componentPortal); + cakeOverlayRef.attach(templatePortal); + + expect(pizzaOverlayRef.overlayElement.nextSibling) + .toBeTruthy('Expected pizza to be on the bottom.'); + expect(cakeOverlayRef.overlayElement.nextSibling) + .toBeFalsy('Expected cake to be on top.'); + + pizzaOverlayRef.dispose(); + cakeOverlayRef.detach(); + + pizzaOverlayRef = overlay.create(); + pizzaOverlayRef.attach(componentPortal); + cakeOverlayRef.attach(templatePortal); + + expect(pizzaOverlayRef.overlayElement.nextSibling) + .toBeTruthy('Expected pizza to still be on the bottom.'); + expect(cakeOverlayRef.overlayElement.nextSibling) + .toBeFalsy('Expected cake to still be on top.'); + }); + it('should set the direction', () => { const state = new OverlayState(); state.direction = 'rtl';