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.
This commit is contained in:
Kristiyan Kostadinov
2018-01-23 16:51:50 +01:00
committed by Jeremy Elbourn
parent 69270efb7e
commit df447674a9
3 changed files with 51 additions and 11 deletions
+34 -11
View File
@@ -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: `
<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()"
@@ -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');
@@ -329,8 +354,6 @@ class ConnectedOverlayDirectiveTest {
});
detachHandler = jasmine.createSpy('detachHandler');
attachResult: HTMLElement;
@ViewChild(CdkConnectedOverlay) connectedOverlayDirective: CdkConnectedOverlay;
}
@Component({
+8
View File
@@ -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();
}
@@ -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