mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(scrolling): implement ngOnDestroy in ScrollDispatcher (#9608)
Sets up some cleanup logic in the `ScrollDispatcher` in case the module is unloaded.
This commit is contained in:
committed by
Jeremy Elbourn
parent
b42fcb9ca8
commit
fd17cf2813
@@ -180,6 +180,22 @@ describe('Scroll Dispatcher', () => {
|
||||
.toBe(4, 'Expected scrollable count to stay the same');
|
||||
});
|
||||
|
||||
it('should remove the global subscription on destroy', () => {
|
||||
expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.');
|
||||
|
||||
const subscription = scroll.scrolled(0).subscribe(() => {});
|
||||
|
||||
expect(scroll._globalSubscription).toBeTruthy(
|
||||
'Expected global listeners after a subscription has been added.');
|
||||
|
||||
scroll.ngOnDestroy();
|
||||
|
||||
expect(scroll._globalSubscription).toBeNull(
|
||||
'Expected global listeners to have been removed after the subscription has stopped.');
|
||||
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementRef, Injectable, NgZone, Optional, SkipSelf} from '@angular/core';
|
||||
import {ElementRef, Injectable, NgZone, Optional, SkipSelf, OnDestroy} from '@angular/core';
|
||||
import {Platform} from '@angular/cdk/platform';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
import {Subscription} from 'rxjs/Subscription';
|
||||
@@ -26,7 +26,7 @@ export const DEFAULT_SCROLL_TIME = 20;
|
||||
* Scrollable references emit a scrolled event.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ScrollDispatcher {
|
||||
export class ScrollDispatcher implements OnDestroy {
|
||||
constructor(private _ngZone: NgZone, private _platform: Platform) { }
|
||||
|
||||
/** Subject for notifying that a registered scrollable reference element has been scrolled. */
|
||||
@@ -97,14 +97,18 @@ export class ScrollDispatcher {
|
||||
subscription.unsubscribe();
|
||||
this._scrolledCount--;
|
||||
|
||||
if (this._globalSubscription && !this._scrolledCount) {
|
||||
this._globalSubscription.unsubscribe();
|
||||
this._globalSubscription = null;
|
||||
if (!this._scrolledCount) {
|
||||
this._removeGlobalListener();
|
||||
}
|
||||
};
|
||||
}) : observableOf<void>();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._removeGlobalListener();
|
||||
this.scrollContainers.forEach((_, container) => this.deregister(container));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable that emits whenever any of the
|
||||
* scrollable ancestors of an element are scrolled.
|
||||
@@ -146,12 +150,20 @@ export class ScrollDispatcher {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Sets up the global scroll and resize listeners. */
|
||||
/** Sets up the global scroll listeners. */
|
||||
private _addGlobalListener() {
|
||||
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
|
||||
return fromEvent(window.document, 'scroll').subscribe(() => this._scrolled.next());
|
||||
});
|
||||
}
|
||||
|
||||
/** Cleans up the global scroll listener. */
|
||||
private _removeGlobalListener() {
|
||||
if (this._globalSubscription) {
|
||||
this._globalSubscription.unsubscribe();
|
||||
this._globalSubscription = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @docs-private */
|
||||
|
||||
Reference in New Issue
Block a user