From a306a8e669744be1ce43910238b84df6e86684b0 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 23 Feb 2017 01:37:55 +0100 Subject: [PATCH] fix(connected-position): error if none of the initial positions fit in viewport (#3189) Fixes an error in the `recalculateLastPosition` method that gets thrown if none of the element's positions fit inside the viewport. These changes default to the first preferred position, if there was no previously-matched position. Relates #3183. --- .../connected-position-strategy.spec.ts | 26 +++++++++++++++++++ .../position/connected-position-strategy.ts | 6 ++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lib/core/overlay/position/connected-position-strategy.spec.ts b/src/lib/core/overlay/position/connected-position-strategy.spec.ts index 8829ee367394..067a87c64939 100644 --- a/src/lib/core/overlay/position/connected-position-strategy.spec.ts +++ b/src/lib/core/overlay/position/connected-position-strategy.spec.ts @@ -261,6 +261,32 @@ describe('ConnectedPositionStrategy', () => { 'Expected overlay to be re-aligned to the trigger in the previous position.'); }); + it('should default to the initial position, if no positions fit in the viewport', () => { + // Use the fake viewport ruler because we don't know *exactly* how big the viewport is. + fakeViewportRuler.fakeRect = { + top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500 + }; + positionBuilder = new OverlayPositionBuilder(fakeViewportRuler); + + // Make the origin element taller than the viewport. + originElement.style.height = '1000px'; + originElement.style.top = '0'; + originRect = originElement.getBoundingClientRect(); + + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'start', originY: 'top'}, + {overlayX: 'start', overlayY: 'bottom'}); + + strategy.apply(overlayElement); + strategy.recalculateLastPosition(); + + let overlayRect = overlayElement.getBoundingClientRect(); + + expect(overlayRect.bottom).toBe(originRect.top, + 'Expected overlay to be re-aligned to the trigger in the initial position.'); + }); + it('should position a panel properly when rtl', () => { // must make the overlay longer than the origin to properly test attachment overlayElement.style.width = `500px`; diff --git a/src/lib/core/overlay/position/connected-position-strategy.ts b/src/lib/core/overlay/position/connected-position-strategy.ts index 44b739bcebde..2eda42461e93 100644 --- a/src/lib/core/overlay/position/connected-position-strategy.ts +++ b/src/lib/core/overlay/position/connected-position-strategy.ts @@ -151,10 +151,10 @@ export class ConnectedPositionStrategy implements PositionStrategy { const originRect = this._origin.getBoundingClientRect(); const overlayRect = this._pane.getBoundingClientRect(); const viewportRect = this._viewportRuler.getViewportRect(); + const lastPosition = this._lastConnectedPosition || this._preferredPositions[0]; - let originPoint = this._getOriginConnectionPoint(originRect, this._lastConnectedPosition); - let overlayPoint = - this._getOverlayPoint(originPoint, overlayRect, viewportRect, this._lastConnectedPosition); + let originPoint = this._getOriginConnectionPoint(originRect, lastPosition); + let overlayPoint = this._getOverlayPoint(originPoint, overlayRect, viewportRect, lastPosition); this._setElementPosition(this._pane, overlayPoint); }