diff --git a/src/lib/core/overlay/overlay-directives.spec.ts b/src/lib/core/overlay/overlay-directives.spec.ts index 126e89fe867..386525fb1d2 100644 --- a/src/lib/core/overlay/overlay-directives.spec.ts +++ b/src/lib/core/overlay/overlay-directives.spec.ts @@ -29,16 +29,25 @@ describe('Overlay directives', () => { fixture.detectChanges(); }); + /** Returns the current open overlay pane element. */ + function getPaneElement() { + return overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + } + it(`should attach the overlay based on the open property`, () => { fixture.componentInstance.isOpen = true; fixture.detectChanges(); expect(overlayContainerElement.textContent).toContain('Menu content'); + expect(getPaneElement().style.pointerEvents) + .toBeFalsy('Expected the overlay pane to enable pointerEvents when attached.'); fixture.componentInstance.isOpen = false; fixture.detectChanges(); expect(overlayContainerElement.textContent).toBe(''); + expect(getPaneElement().style.pointerEvents) + .toBe('none', 'Expected the overlay pane to disable pointerEvents when detached.'); }); it('should destroy the overlay when the directive is destroyed', () => { @@ -47,6 +56,8 @@ describe('Overlay directives', () => { fixture.destroy(); expect(overlayContainerElement.textContent.trim()).toBe(''); + expect(getPaneElement()) + .toBeFalsy('Expected the overlay pane element to be removed when disposed.'); }); it('should use a connected position strategy with a default set of positions', () => { diff --git a/src/lib/core/overlay/overlay-ref.ts b/src/lib/core/overlay/overlay-ref.ts index 5feff92c792..c155303622d 100644 --- a/src/lib/core/overlay/overlay-ref.ts +++ b/src/lib/core/overlay/overlay-ref.ts @@ -35,10 +35,15 @@ export class OverlayRef implements PortalHost { } let attachResult = this._portalHost.attach(portal); + + // Update the pane element with the given state configuration. this.updateSize(); this.updateDirection(); this.updatePosition(); + // Enable pointer events for the overlay pane element. + this._togglePointerEvents(true); + return attachResult; } @@ -48,6 +53,12 @@ export class OverlayRef implements PortalHost { */ detach(): Promise { this._detachBackdrop(); + + // When the overlay is detached, the pane element should disable pointer events. + // This is necessary because otherwise the pane element will cover the page and disable + // pointer events therefore. Depends on the position strategy and the applied pane boundaries. + this._togglePointerEvents(false); + return this._portalHost.detach(); } @@ -115,6 +126,11 @@ export class OverlayRef implements PortalHost { } } + /** Toggles the pointer events for the overlay pane element. */ + private _togglePointerEvents(enablePointer: boolean) { + this._pane.style.pointerEvents = enablePointer ? null : 'none'; + } + /** Attaches a backdrop for this overlay. */ private _attachBackdrop() { this._backdropElement = document.createElement('div'); diff --git a/src/lib/core/overlay/overlay.spec.ts b/src/lib/core/overlay/overlay.spec.ts index 4ebbd7245e0..e4854e2e7d9 100644 --- a/src/lib/core/overlay/overlay.spec.ts +++ b/src/lib/core/overlay/overlay.spec.ts @@ -62,6 +62,23 @@ describe('Overlay', () => { expect(overlayContainerElement.textContent).toBe(''); }); + it('should disable pointer events of the pane element if detached', () => { + let overlayRef = overlay.create(); + let paneElement = overlayRef.overlayElement; + + overlayRef.attach(componentPortal); + + expect(paneElement.childNodes.length).not.toBe(0); + expect(paneElement.style.pointerEvents) + .toBeFalsy('Expected the overlay pane to enable pointerEvents when attached.'); + + overlayRef.detach(); + + expect(paneElement.childNodes.length).toBe(0); + expect(paneElement.style.pointerEvents) + .toBe('none', 'Expected the overlay pane to disable pointerEvents when detached.'); + }); + it('should open multiple overlays', () => { let pizzaOverlayRef = overlay.create(); pizzaOverlayRef.attach(componentPortal); diff --git a/src/lib/core/portal/dom-portal-host.ts b/src/lib/core/portal/dom-portal-host.ts index 31d151d9f97..d44b9e0a901 100644 --- a/src/lib/core/portal/dom-portal-host.ts +++ b/src/lib/core/portal/dom-portal-host.ts @@ -65,11 +65,14 @@ export class DomPortalHost extends BasePortalHost { let viewContainer = portal.viewContainerRef; let viewRef = viewContainer.createEmbeddedView(portal.templateRef); + // The method `createEmbeddedView` will add the view as a child of the viewContainer. + // But for the DomPortalHost the view can be added everywhere in the DOM (e.g Overlay Container) + // To move the view to the specified host element. We just re-append the existing root nodes. viewRef.rootNodes.forEach(rootNode => this._hostDomElement.appendChild(rootNode)); this.setDisposeFn((() => { let index = viewContainer.indexOf(viewRef); - if (index != -1) { + if (index !== -1) { viewContainer.remove(index); } }));