Skip to content

Commit 37b9664

Browse files
crisbetojelbourn
authored andcommitted
fix(overlay): only dispatch position change event if requested (#19785)
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. (cherry picked from commit bbf5670)
1 parent 5892285 commit 37b9664

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)