Skip to content

Commit 8952d09

Browse files
committed
fix(overlay): only dispatch position change event if requested
The `ConnectedOverlayPositionChange` event can be expensive to calculate since it contains information about the scroll position. We have some logic in the position strategy about not emitting it if there are no observers, but in the `CdkConnectedOverlay` directive we were always subscribing in order to proxy it to the output. These changes add some logic to only subscribe when necessary.
1 parent 2a97418 commit 8952d09

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

src/cdk/overlay/overlay-directives.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
ViewContainerRef,
2727
} from '@angular/core';
2828
import {Subscription} from 'rxjs';
29+
import {takeWhile} from 'rxjs/operators';
2930
import {Overlay} from './overlay';
3031
import {OverlayConfig} from './overlay-config';
3132
import {OverlayRef} from './overlay-ref';
@@ -111,6 +112,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
111112
private _flexibleDimensions = false;
112113
private _push = false;
113114
private _backdropSubscription = Subscription.EMPTY;
115+
private _positionSubscription = Subscription.EMPTY;
114116
private _offsetX: number;
115117
private _offsetY: number;
116118
private _position: FlexibleConnectedPositionStrategy;
@@ -251,6 +253,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
251253
}
252254

253255
this._backdropSubscription.unsubscribe();
256+
this._positionSubscription.unsubscribe();
254257
}
255258

256259
ngOnChanges(changes: SimpleChanges) {
@@ -355,10 +358,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
355358
/** Returns the position strategy of the overlay to be set on the overlay config */
356359
private _createPositionStrategy(): FlexibleConnectedPositionStrategy {
357360
const strategy = this._overlay.position().flexibleConnectedTo(this.origin.elementRef);
358-
359361
this._updatePositionStrategy(strategy);
360-
strategy.positionChanges.subscribe(p => this.positionChange.emit(p));
361-
362362
return strategy;
363363
}
364364

@@ -383,6 +383,22 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
383383
} else {
384384
this._backdropSubscription.unsubscribe();
385385
}
386+
387+
this._positionSubscription.unsubscribe();
388+
389+
// Only subscribe to `positionChanges` if requested, because putting
390+
// together all the information for it can be expensive.
391+
if (this.positionChange.observers.length > 0) {
392+
this._positionSubscription = this._position.positionChanges
393+
.pipe(takeWhile(() => this.positionChange.observers.length > 0))
394+
.subscribe(position => {
395+
this.positionChange.emit(position);
396+
397+
if (this.positionChange.observers.length === 0) {
398+
this._positionSubscription.unsubscribe();
399+
}
400+
});
401+
}
386402
}
387403

388404
/** Detaches the overlay and unsubscribes to backdrop clicks if backdrop exists */
@@ -393,6 +409,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
393409
}
394410

395411
this._backdropSubscription.unsubscribe();
412+
this._positionSubscription.unsubscribe();
396413
}
397414

398415
static ngAcceptInputType_hasBackdrop: BooleanInput;

0 commit comments

Comments
 (0)