mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(overlay): emit position change event (#1832)
This commit is contained in:
@@ -2,6 +2,7 @@ import {ElementRef} from '@angular/core';
|
||||
import {ConnectedPositionStrategy} from './connected-position-strategy';
|
||||
import {ViewportRuler} from './viewport-ruler';
|
||||
import {OverlayPositionBuilder} from './overlay-position-builder';
|
||||
import {ConnectedOverlayPositionChange} from './connected-position';
|
||||
|
||||
|
||||
// Default width and height of the overlay and origin panels throughout these tests.
|
||||
@@ -259,6 +260,33 @@ describe('ConnectedPositionStrategy', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should emit onPositionChange event when position changes', () => {
|
||||
// force the overlay to open in a fallback position
|
||||
fakeViewportRuler.fakeRect = {
|
||||
top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500
|
||||
};
|
||||
positionBuilder = new OverlayPositionBuilder(fakeViewportRuler);
|
||||
originElement.style.top = '200px';
|
||||
originElement.style.left = '475px';
|
||||
|
||||
strategy = positionBuilder.connectedTo(
|
||||
fakeElementRef,
|
||||
{originX: 'end', originY: 'center'},
|
||||
{overlayX: 'start', overlayY: 'center'})
|
||||
.withFallbackPosition(
|
||||
{originX: 'start', originY: 'bottom'},
|
||||
{overlayX: 'end', overlayY: 'top'});
|
||||
|
||||
const positionChangeHandler = jasmine.createSpy('positionChangeHandler');
|
||||
strategy.onPositionChange.first().subscribe(positionChangeHandler);
|
||||
|
||||
strategy.apply(overlayElement);
|
||||
expect(positionChangeHandler).toHaveBeenCalled();
|
||||
expect(positionChangeHandler.calls.mostRecent().args[0])
|
||||
.toEqual(jasmine.any(ConnectedOverlayPositionChange),
|
||||
`Expected strategy to emit an instance of ConnectedOverlayPositionChange.`);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Run all tests for connecting the overlay to the origin such that first preferred
|
||||
|
||||
@@ -5,9 +5,11 @@ import {applyCssTransform} from '../../style/apply-transform';
|
||||
import {
|
||||
ConnectionPositionPair,
|
||||
OriginConnectionPosition,
|
||||
OverlayConnectionPosition
|
||||
OverlayConnectionPosition,
|
||||
ConnectedOverlayPositionChange
|
||||
} from './connected-position';
|
||||
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
/**
|
||||
* A strategy for positioning overlays. Using this strategy, an overlay is given an
|
||||
@@ -36,6 +38,13 @@ export class ConnectedPositionStrategy implements PositionStrategy {
|
||||
/** The origin element against which the overlay will be positioned. */
|
||||
private _origin: HTMLElement;
|
||||
|
||||
private _onPositionChange:
|
||||
Subject<ConnectedOverlayPositionChange> = new Subject<ConnectedOverlayPositionChange>();
|
||||
|
||||
/** Emits an event when the connection point changes. */
|
||||
get onPositionChange(): Observable<ConnectedOverlayPositionChange> {
|
||||
return this._onPositionChange.asObservable();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _connectedTo: ElementRef,
|
||||
@@ -64,6 +73,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
|
||||
// We use the viewport rect to determine whether a position would go off-screen.
|
||||
const viewportRect = this._viewportRuler.getViewportRect();
|
||||
let firstOverlayPoint: Point = null;
|
||||
let isFirstPosition = true;
|
||||
|
||||
// We want to place the overlay in the first of the preferred positions such that the
|
||||
// overlay fits on-screen.
|
||||
@@ -77,8 +87,12 @@ export class ConnectedPositionStrategy implements PositionStrategy {
|
||||
// If the overlay in the calculated position fits on-screen, put it there and we're done.
|
||||
if (this._willOverlayFitWithinViewport(overlayPoint, overlayRect, viewportRect)) {
|
||||
this._setElementPosition(element, overlayPoint);
|
||||
if (!isFirstPosition) {
|
||||
this._onPositionChange.next(new ConnectedOverlayPositionChange(pos));
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
isFirstPosition = false;
|
||||
}
|
||||
|
||||
// TODO(jelbourn): fallback behavior for when none of the preferred positions fit on-screen.
|
||||
|
||||
@@ -31,3 +31,8 @@ export class ConnectionPositionPair {
|
||||
this.overlayY = overlay.overlayY;
|
||||
}
|
||||
}
|
||||
|
||||
/** The change event emitted by the strategy when a fallback position is used. */
|
||||
export class ConnectedOverlayPositionChange {
|
||||
constructor(public connectionPair: ConnectionPositionPair) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user