diff --git a/src/lib/core/overlay/overlay-directives.spec.ts b/src/lib/core/overlay/overlay-directives.spec.ts index daf545a9452c..8e7c98bd6918 100644 --- a/src/lib/core/overlay/overlay-directives.spec.ts +++ b/src/lib/core/overlay/overlay-directives.spec.ts @@ -4,6 +4,7 @@ import {By} from '@angular/platform-browser'; import {ConnectedOverlayDirective, OverlayModule} from './overlay-directives'; import {OverlayContainer} from './overlay-container'; import {ConnectedPositionStrategy} from './position/connected-position-strategy'; +import {ConnectedOverlayPositionChange} from './position/connected-position'; describe('Overlay directives', () => { @@ -110,18 +111,6 @@ describe('Overlay directives', () => { expect(backdrop.classList).toContain('md-test-class'); }); - it('should emit backdropClick appropriately', () => { - fixture.componentInstance.hasBackdrop = true; - fixture.componentInstance.isOpen = true; - fixture.detectChanges(); - - const backdrop = overlayContainerElement.querySelector('.md-overlay-backdrop') as HTMLElement; - backdrop.click(); - fixture.detectChanges(); - - expect(fixture.componentInstance.backdropClicked).toBe(true); - }); - it('should set the offsetX', () => { const trigger = fixture.debugElement.query(By.css('button')).nativeElement; const startX = trigger.getBoundingClientRect().left; @@ -154,6 +143,32 @@ describe('Overlay directives', () => { }); + describe('outputs', () => { + it('should emit backdropClick appropriately', () => { + fixture.componentInstance.hasBackdrop = true; + fixture.componentInstance.isOpen = true; + fixture.detectChanges(); + + const backdrop = overlayContainerElement.querySelector('.md-overlay-backdrop') as HTMLElement; + backdrop.click(); + fixture.detectChanges(); + + expect(fixture.componentInstance.backdropClicked).toBe(true); + }); + + it('should emit positionChange appropriately', () => { + expect(fixture.componentInstance.positionChangeHandler).not.toHaveBeenCalled(); + fixture.componentInstance.isOpen = true; + fixture.detectChanges(); + + expect(fixture.componentInstance.positionChangeHandler).toHaveBeenCalled(); + expect(fixture.componentInstance.positionChangeHandler.calls.mostRecent().args[0]) + .toEqual(jasmine.any(ConnectedOverlayPositionChange), + `Expected directive to emit an instance of ConnectedOverlayPositionChange.`); + }); + + }); + }); @@ -161,8 +176,9 @@ describe('Overlay directives', () => { template: ` `, }) @@ -174,6 +190,7 @@ class ConnectedOverlayDirectiveTest { offsetY: number = 0; hasBackdrop: boolean; backdropClicked = false; + positionChangeHandler = jasmine.createSpy('positionChangeHandler'); @ViewChild(ConnectedOverlayDirective) connectedOverlayDirective: ConnectedOverlayDirective; } diff --git a/src/lib/core/overlay/overlay-directives.ts b/src/lib/core/overlay/overlay-directives.ts index 14577fa6c239..ea1bbade35c7 100644 --- a/src/lib/core/overlay/overlay-directives.ts +++ b/src/lib/core/overlay/overlay-directives.ts @@ -15,7 +15,10 @@ import {Overlay, OVERLAY_PROVIDERS} from './overlay'; import {OverlayRef} from './overlay-ref'; import {TemplatePortal} from '../portal/portal'; import {OverlayState} from './overlay-state'; -import {ConnectionPositionPair} from './position/connected-position'; +import { + ConnectionPositionPair, + ConnectedOverlayPositionChange +} from './position/connected-position'; import {PortalModule} from '../portal/portal-directives'; import {ConnectedPositionStrategy} from './position/connected-position-strategy'; import {Subscription} from 'rxjs/Subscription'; @@ -63,6 +66,7 @@ export class ConnectedOverlayDirective implements OnDestroy { private _open = false; private _hasBackdrop = false; private _backdropSubscription: Subscription; + private _positionSubscription: Subscription; @Input() origin: OverlayOrigin; @Input() positions: ConnectionPositionPair[]; @@ -105,6 +109,7 @@ export class ConnectedOverlayDirective implements OnDestroy { /** Event emitted when the backdrop is clicked. */ @Output() backdropClick = new EventEmitter(); + @Output() positionChange = new EventEmitter(); // TODO(jelbourn): inputs for size, scroll behavior, animation, etc. @@ -169,11 +174,27 @@ export class ConnectedOverlayDirective implements OnDestroy { const originPoint = {originX: pos.originX, originY: pos.originY}; const overlayPoint = {overlayX: pos.overlayX, overlayY: pos.overlayY}; - return this._overlay.position() + const strategy = this._overlay.position() .connectedTo(this.origin.elementRef, originPoint, overlayPoint) .withDirection(this.dir) .withOffsetX(this.offsetX) .withOffsetY(this.offsetY); + + this._handlePositionChanges(strategy); + + return strategy; + } + + private _handlePositionChanges(strategy: ConnectedPositionStrategy): void { + for (let i = 1; i < this.positions.length; i++) { + strategy.withFallbackPosition( + {originX: this.positions[i].originX, originY: this.positions[i].originY}, + {overlayX: this.positions[i].overlayX, overlayY: this.positions[i].overlayY} + ); + } + + this._positionSubscription = + strategy.onPositionChange.subscribe(pos => this.positionChange.emit(pos)); } /** Attaches the overlay and subscribes to backdrop clicks if backdrop exists */ @@ -214,6 +235,9 @@ export class ConnectedOverlayDirective implements OnDestroy { if (this._backdropSubscription) { this._backdropSubscription.unsubscribe(); } + if (this._positionSubscription) { + this._positionSubscription.unsubscribe(); + } } }