Skip to content

Commit

Permalink
fix(overlay): unable to change CdkConnectedOverlay origin dynamically (
Browse files Browse the repository at this point in the history
…#9358)

Fixes the `CdkConnectedOverlay` not handling changes of its `origin` after it's opened for the first time.

Fixes #9353.
  • Loading branch information
crisbeto authored and jelbourn committed Jan 23, 2018
1 parent 69270ef commit df44767
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 11 deletions.
45 changes: 34 additions & 11 deletions src/cdk/overlay/overlay-directives.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'}}],
});
});

Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -302,9 +320,11 @@ describe('Overlay directives', () => {

@Component({
template: `
<button cdk-overlay-origin #trigger="cdkOverlayOrigin">Toggle menu</button>
<button cdk-overlay-origin id="trigger" #trigger="cdkOverlayOrigin">Toggle menu</button>
<button cdk-overlay-origin id="otherTrigger" #otherTrigger="cdkOverlayOrigin">Toggle menu</button>
<ng-template cdk-connected-overlay [open]="isOpen" [width]="width" [height]="height"
[origin]="trigger"
[cdkConnectedOverlayOrigin]="triggerOverride || trigger"
[hasBackdrop]="hasBackdrop" backdropClass="mat-test-class"
(backdropClick)="backdropClicked=true" [offsetX]="offsetX" [offsetY]="offsetY"
(positionChange)="positionChangeHandler($event)" (attach)="attachHandler()"
Expand All @@ -313,13 +333,18 @@ describe('Overlay directives', () => {
</ng-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');
Expand All @@ -329,8 +354,6 @@ class ConnectedOverlayDirectiveTest {
});
detachHandler = jasmine.createSpy('detachHandler');
attachResult: HTMLElement;

@ViewChild(CdkConnectedOverlay) connectedOverlayDirective: CdkConnectedOverlay;
}

@Component({
Expand Down
8 changes: 8 additions & 0 deletions src/cdk/overlay/overlay-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
9 changes: 9 additions & 0 deletions src/cdk/overlay/position/connected-position-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit df44767

Please sign in to comment.