Skip to content

Commit 4b62f0a

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 49de56c commit 4b62f0a

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';
@@ -113,6 +114,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
113114
private _backdropSubscription = Subscription.EMPTY;
114115
private _attachSubscription = Subscription.EMPTY;
115116
private _detachSubscription = Subscription.EMPTY;
117+
private _positionSubscription = Subscription.EMPTY;
116118
private _offsetX: number;
117119
private _offsetY: number;
118120
private _position: FlexibleConnectedPositionStrategy;
@@ -254,6 +256,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
254256
this._attachSubscription.unsubscribe();
255257
this._detachSubscription.unsubscribe();
256258
this._backdropSubscription.unsubscribe();
259+
this._positionSubscription.unsubscribe();
257260

258261
if (this._overlayRef) {
259262
this._overlayRef.dispose();
@@ -367,10 +370,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
367370
/** Returns the position strategy of the overlay to be set on the overlay config */
368371
private _createPositionStrategy(): FlexibleConnectedPositionStrategy {
369372
const strategy = this._overlay.position().flexibleConnectedTo(this.origin.elementRef);
370-
371373
this._updatePositionStrategy(strategy);
372-
strategy.positionChanges.subscribe(p => this.positionChange.emit(p));
373-
374374
return strategy;
375375
}
376376

@@ -394,6 +394,22 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
394394
} else {
395395
this._backdropSubscription.unsubscribe();
396396
}
397+
398+
this._positionSubscription.unsubscribe();
399+
400+
// Only subscribe to `positionChanges` if requested, because putting
401+
// together all the information for it can be expensive.
402+
if (this.positionChange.observers.length > 0) {
403+
this._positionSubscription = this._position.positionChanges
404+
.pipe(takeWhile(() => this.positionChange.observers.length > 0))
405+
.subscribe(position => {
406+
this.positionChange.emit(position);
407+
408+
if (this.positionChange.observers.length === 0) {
409+
this._positionSubscription.unsubscribe();
410+
}
411+
});
412+
}
397413
}
398414

399415
/** Detaches the overlay and unsubscribes to backdrop clicks if backdrop exists */
@@ -403,6 +419,7 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
403419
}
404420

405421
this._backdropSubscription.unsubscribe();
422+
this._positionSubscription.unsubscribe();
406423
}
407424

408425
static ngAcceptInputType_hasBackdrop: BooleanInput;

0 commit comments

Comments
 (0)