From a7b4ba4ce86113c3361bb04fe78db12c5b523898 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 17 Mar 2018 10:56:24 +0100 Subject: [PATCH] fix(overlay): clear last calculated position when new set of positions is provided In the `FlexibleConnectedPositionStrategy` once we apply a position, we save a reference to it in order to be able to reuse it if the consumer wants to recalculate the overlay dimensions, however that cached position isn't being cleared. This means that if consumer were to provide a new set of positions and tried to re-apply the last calculated position, the cached position may no longer be a part of the list of preferred positions. These changes will clear the last position if it's not a part of the preferred positions anymore. Relates to #10457. --- .../position/connected-position-strategy.ts | 2 +- ...exible-connected-position-strategy.spec.ts | 39 +++++++++++++++++++ .../flexible-connected-position-strategy.ts | 9 ++++- .../position/overlay-position-builder.ts | 2 + src/lib/select/select.html | 3 +- 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/cdk/overlay/position/connected-position-strategy.ts b/src/cdk/overlay/position/connected-position-strategy.ts index 6939c8b1d268..4058d1b0864e 100644 --- a/src/cdk/overlay/position/connected-position-strategy.ts +++ b/src/cdk/overlay/position/connected-position-strategy.ts @@ -31,7 +31,7 @@ import {FlexibleConnectedPositionStrategy} from './flexible-connected-position-s * a point on the origin element that is connected to a point on the overlay element. For example, * a basic dropdown is connecting the bottom-left corner of the origin to the top-left corner * of the overlay. - * @deprecated + * @deprecated Use `FlexibleConnectedPositionStrategy` instead. * @deletion-target 7.0.0 */ export class ConnectedPositionStrategy implements PositionStrategy { diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts index 5d1b625276a7..422b6bb69840 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts @@ -633,6 +633,45 @@ describe('FlexibleConnectedPositionStrategy', () => { expect(recalcSpy).toHaveBeenCalled(); }); + it('should not retain the last preferred position when overriding the positions', () => { + originElement.style.top = '100px'; + originElement.style.left = '100px'; + + const originRect = originElement.getBoundingClientRect(); + + positionStrategy.withPositions([{ + originX: 'start', + originY: 'top', + overlayX: 'start', + overlayY: 'top', + offsetX: 10, + offsetY: 20 + }]); + + attachOverlay({positionStrategy}); + + let overlayRect = overlayRef.overlayElement.getBoundingClientRect(); + + expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top) + 20); + expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left) + 10); + + positionStrategy.withPositions([{ + originX: 'start', + originY: 'top', + overlayX: 'start', + overlayY: 'top', + offsetX: 20, + offsetY: 40 + }]); + + positionStrategy.reapplyLastPosition(); + + overlayRect = overlayRef.overlayElement.getBoundingClientRect(); + + expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top) + 40); + expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left) + 20); + }); + /** * Run all tests for connecting the overlay to the origin such that first preferred * position does not go off-screen. We do this because there are several cases where we diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.ts index 696cf6ce313e..2d2a3a91b7e9 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.ts @@ -95,7 +95,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { private _boundingBox: HTMLElement | null; /** The last position to have been calculated as the best fit position. */ - private _lastPosition: ConnectedPosition; + private _lastPosition: ConnectedPosition | null; /** Subject that emits whenever the position changes. */ private _positionChanges = new Subject(); @@ -305,6 +305,13 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { */ withPositions(positions: ConnectedPosition[]): this { this._preferredPositions = positions; + + // If the last calculated position object isn't part of the positions anymore, clear + // it in order to avoid it being picked up if the consumer tries to re-apply. + if (positions.indexOf(this._lastPosition!) === -1) { + this._lastPosition = null; + } + return this; } diff --git a/src/cdk/overlay/position/overlay-position-builder.ts b/src/cdk/overlay/position/overlay-position-builder.ts index 78fa4ad61e79..0c136481bcb5 100644 --- a/src/cdk/overlay/position/overlay-position-builder.ts +++ b/src/cdk/overlay/position/overlay-position-builder.ts @@ -34,6 +34,8 @@ export class OverlayPositionBuilder { * @param elementRef * @param originPos * @param overlayPos + * @deprecated Use `flexibleConnectedTo` instead. + * @deletion-target 7.0.0 */ connectedTo( elementRef: ElementRef, diff --git a/src/lib/select/select.html b/src/lib/select/select.html index e0da14ceb8e4..85c639b9698e 100644 --- a/src/lib/select/select.html +++ b/src/lib/select/select.html @@ -15,11 +15,10 @@
-