From df447674a93769c2a2d33bb26e9db6d38035ef9a Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 23 Jan 2018 16:51:50 +0100 Subject: [PATCH] fix(overlay): unable to change CdkConnectedOverlay origin dynamically (#9358) Fixes the `CdkConnectedOverlay` not handling changes of its `origin` after it's opened for the first time. Fixes #9353. --- src/cdk/overlay/overlay-directives.spec.ts | 45 ++++++++++++++----- src/cdk/overlay/overlay-directives.ts | 8 ++++ .../position/connected-position-strategy.ts | 9 ++++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/cdk/overlay/overlay-directives.spec.ts b/src/cdk/overlay/overlay-directives.spec.ts index b2bf2ed39e0..f37093350b2 100644 --- a/src/cdk/overlay/overlay-directives.spec.ts +++ b/src/cdk/overlay/overlay-directives.spec.ts @@ -20,11 +20,7 @@ describe('Overlay directives', () => { TestBed.configureTestingModule({ imports: [OverlayModule], declarations: [ConnectedOverlayDirectiveTest, ConnectedOverlayPropertyInitOrder], - providers: [ - {provide: Directionality, useFactory: () => { - return dir = {value: 'ltr'}; - }} - ], + providers: [{provide: Directionality, useFactory: () => dir = {value: 'ltr'}}], }); }); @@ -250,6 +246,28 @@ describe('Overlay directives', () => { .toBe('105px', `Expected overlay directive to reflect new offsetY if it changes.`); }); + it('should be able to update the origin after init', () => { + const testComponent = fixture.componentInstance; + + testComponent.isOpen = true; + fixture.detectChanges(); + + let triggerRect = fixture.nativeElement.querySelector('#trigger').getBoundingClientRect(); + let overlayRect = getPaneElement().getBoundingClientRect(); + + expect(Math.floor(triggerRect.left)).toBe(Math.floor(overlayRect.left)); + expect(Math.floor(triggerRect.bottom)).toBe(Math.floor(overlayRect.top)); + + testComponent.triggerOverride = testComponent.otherTrigger; + fixture.detectChanges(); + + triggerRect = fixture.nativeElement.querySelector('#otherTrigger').getBoundingClientRect(); + overlayRect = getPaneElement().getBoundingClientRect(); + + expect(Math.floor(triggerRect.left)).toBe(Math.floor(overlayRect.left)); + expect(Math.floor(triggerRect.bottom)).toBe(Math.floor(overlayRect.top)); + }); + }); describe('outputs', () => { @@ -302,9 +320,11 @@ describe('Overlay directives', () => { @Component({ template: ` - + + + { `, }) class ConnectedOverlayDirectiveTest { + @ViewChild(CdkConnectedOverlay) connectedOverlayDirective: CdkConnectedOverlay; + @ViewChild('trigger') trigger: CdkOverlayOrigin; + @ViewChild('otherTrigger') otherTrigger: CdkOverlayOrigin; + isOpen = false; width: number | string; height: number | string; minWidth: number | string; minHeight: number | string; - offsetX: number = 0; - offsetY: number = 0; + offsetX = 0; + offsetY = 0; + triggerOverride: CdkOverlayOrigin; hasBackdrop: boolean; backdropClicked = false; positionChangeHandler = jasmine.createSpy('positionChangeHandler'); @@ -329,8 +354,6 @@ class ConnectedOverlayDirectiveTest { }); detachHandler = jasmine.createSpy('detachHandler'); attachResult: HTMLElement; - - @ViewChild(CdkConnectedOverlay) connectedOverlayDirective: CdkConnectedOverlay; } @Component({ diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index 35cbfdb1190..54dc66465dc 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -256,6 +256,14 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { } ngOnChanges(changes: SimpleChanges) { + if ((changes['origin'] || changes['_deprecatedOrigin']) && this._position) { + this._position.setOrigin(this.origin.elementRef); + + if (this.open) { + this._position.apply(); + } + } + if (changes['open'] || changes['_deprecatedOpen']) { this.open ? this._attachOverlay() : this._detachOverlay(); } diff --git a/src/cdk/overlay/position/connected-position-strategy.ts b/src/cdk/overlay/position/connected-position-strategy.ts index 6dd2d337e12..ad8561e1742 100644 --- a/src/cdk/overlay/position/connected-position-strategy.ts +++ b/src/cdk/overlay/position/connected-position-strategy.ts @@ -265,6 +265,15 @@ export class ConnectedPositionStrategy implements PositionStrategy { return this; } + /** + * Sets the origin element, relative to which to position the overlay. + * @param origin Reference to the new origin element. + */ + setOrigin(origin: ElementRef): this { + this._origin = origin.nativeElement; + return this; + } + /** * Gets the horizontal (x) "start" dimension based on whether the overlay is in an RTL context. * @param rect