diff --git a/src/cdk/scrolling/scroll-dispatcher.spec.ts b/src/cdk/scrolling/scroll-dispatcher.spec.ts index e16d3278afe7..7e8fc9d1a9d0 100644 --- a/src/cdk/scrolling/scroll-dispatcher.spec.ts +++ b/src/cdk/scrolling/scroll-dispatcher.spec.ts @@ -143,6 +143,26 @@ describe('Scroll Dispatcher', () => { 'Expected global listeners to have been removed after the subscription has stopped.'); }); + it('should remove global listeners on unsubscribe, despite any other live scrollables', () => { + const fixture = TestBed.createComponent(NestedScrollingComponent); + fixture.detectChanges(); + + expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.'); + expect(scroll.scrollableReferences.size).toBe(4, 'Expected multiple scrollables'); + + const subscription = scroll.scrolled(0).subscribe(() => {}); + + expect(scroll._globalSubscription).toBeTruthy( + 'Expected global listeners after a subscription has been added.'); + + subscription.unsubscribe(); + + expect(scroll._globalSubscription).toBeNull( + 'Expected global listeners to have been removed after the subscription has stopped.'); + expect(scroll.scrollableReferences.size) + .toBe(4, 'Expected scrollable count to stay the same'); + }); + }); }); diff --git a/src/cdk/scrolling/scroll-dispatcher.ts b/src/cdk/scrolling/scroll-dispatcher.ts index 9060f4569bc9..95d5c3667450 100644 --- a/src/cdk/scrolling/scroll-dispatcher.ts +++ b/src/cdk/scrolling/scroll-dispatcher.ts @@ -89,7 +89,7 @@ export class ScrollDispatcher { subscription.unsubscribe(); this._scrolledCount--; - if (this._globalSubscription && !this.scrollableReferences.size && !this._scrolledCount) { + if (this._globalSubscription && !this._scrolledCount) { this._globalSubscription.unsubscribe(); this._globalSubscription = null; } diff --git a/src/cdk/scrolling/viewport-ruler.ts b/src/cdk/scrolling/viewport-ruler.ts index f5d840f4646f..f042899a86e6 100644 --- a/src/cdk/scrolling/viewport-ruler.ts +++ b/src/cdk/scrolling/viewport-ruler.ts @@ -8,7 +8,6 @@ import {Injectable, Optional, SkipSelf, NgZone, OnDestroy} from '@angular/core'; import {Platform} from '@angular/cdk/platform'; -import {ScrollDispatcher} from './scroll-dispatcher'; import {Observable} from 'rxjs/Observable'; import {fromEvent} from 'rxjs/observable/fromEvent'; import {merge} from 'rxjs/observable/merge'; @@ -32,21 +31,19 @@ export class ViewportRuler implements OnDestroy { /** Stream of viewport change events. */ private _change: Observable; - /** Subscriptions to streams that invalidate the cached viewport dimensions. */ - private _invalidateCacheSubscription = Subscription.EMPTY; + /** Subscription to streams that invalidate the cached viewport dimensions. */ + private _invalidateCache: Subscription; - constructor(platform: Platform, ngZone: NgZone, scrollDispatcher: ScrollDispatcher) { + constructor(platform: Platform, ngZone: NgZone) { this._change = platform.isBrowser ? ngZone.runOutsideAngular(() => { return merge(fromEvent(window, 'resize'), fromEvent(window, 'orientationchange')); }) : observableOf(); - // Subscribe to scroll and resize events and update the document rectangle on changes. - this._invalidateCacheSubscription = merge(scrollDispatcher.scrolled(0), this.change()) - .subscribe(() => this._cacheViewportGeometry()); + this._invalidateCache = this.change().subscribe(() => this._cacheViewportGeometry()); } ngOnDestroy() { - this._invalidateCacheSubscription.unsubscribe(); + this._invalidateCache.unsubscribe(); } /** Gets a ClientRect for the viewport's bounds. */ @@ -123,15 +120,14 @@ export class ViewportRuler implements OnDestroy { /** @docs-private */ export function VIEWPORT_RULER_PROVIDER_FACTORY(parentRuler: ViewportRuler, platform: Platform, - ngZone: NgZone, - scrollDispatcher: ScrollDispatcher) { - return parentRuler || new ViewportRuler(platform, ngZone, scrollDispatcher); + ngZone: NgZone) { + return parentRuler || new ViewportRuler(platform, ngZone); } /** @docs-private */ export const VIEWPORT_RULER_PROVIDER = { // If there is already a ViewportRuler available, use that. Otherwise, provide a new one. provide: ViewportRuler, - deps: [[new Optional(), new SkipSelf(), ViewportRuler], Platform, NgZone, ScrollDispatcher], + deps: [[new Optional(), new SkipSelf(), ViewportRuler], Platform, NgZone], useFactory: VIEWPORT_RULER_PROVIDER_FACTORY };