From 707a7ee7a579c384612373b28be1c2df813ce058 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 2 Oct 2018 22:33:35 +0200 Subject: [PATCH] fix(scrolling): viewport ruler resize event running inside the NgZone (#12909) Fixes the `resize` and `orientationchange` events from the `ViewportRuler` being run inside the `NgZone`, even though the intention is that they shouldn't be. The issue comes from the fact that we call `merge` outside the `NgZone`, however the thing that causes the event to be bound is the subscription right after it. Fixes #12883. --- src/cdk/scrolling/viewport-ruler.spec.ts | 12 +++++++++++- src/cdk/scrolling/viewport-ruler.ts | 12 ++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/cdk/scrolling/viewport-ruler.spec.ts b/src/cdk/scrolling/viewport-ruler.spec.ts index 5877c4df8e6..f80fa25ee08 100644 --- a/src/cdk/scrolling/viewport-ruler.spec.ts +++ b/src/cdk/scrolling/viewport-ruler.spec.ts @@ -2,7 +2,7 @@ import {TestBed, inject, fakeAsync, tick} from '@angular/core/testing'; import {ScrollingModule} from './public-api'; import {ViewportRuler} from './viewport-ruler'; import {dispatchFakeEvent} from '@angular/cdk/testing'; - +import {NgZone} from '@angular/core'; // For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight). // The karma config has been set to this for local tests, and it is the default size @@ -140,5 +140,15 @@ describe('ViewportRuler', () => { expect(spy).toHaveBeenCalledTimes(1); subscription.unsubscribe(); })); + + it('should run the resize event outside the NgZone', () => { + const spy = jasmine.createSpy('viewport changed spy'); + const subscription = ruler.change(0).subscribe(() => spy(NgZone.isInAngularZone())); + + dispatchFakeEvent(window, 'resize'); + expect(spy).toHaveBeenCalledWith(false); + subscription.unsubscribe(); + }); + }); }); diff --git a/src/cdk/scrolling/viewport-ruler.ts b/src/cdk/scrolling/viewport-ruler.ts index 4035f0948ce..a94822d531f 100644 --- a/src/cdk/scrolling/viewport-ruler.ts +++ b/src/cdk/scrolling/viewport-ruler.ts @@ -36,11 +36,15 @@ export class ViewportRuler implements OnDestroy { private _invalidateCache: Subscription; constructor(private _platform: Platform, ngZone: NgZone) { - this._change = _platform.isBrowser ? ngZone.runOutsideAngular(() => { - return merge(fromEvent(window, 'resize'), fromEvent(window, 'orientationchange')); - }) : observableOf(); + ngZone.runOutsideAngular(() => { + this._change = _platform.isBrowser ? + merge(fromEvent(window, 'resize'), fromEvent(window, 'orientationchange')) : + observableOf(); - this._invalidateCache = this.change().subscribe(() => this._updateViewportSize()); + // Note that we need to do the subscription inside `runOutsideAngular` + // since subscribing is what causes the event listener to be added. + this._invalidateCache = this.change().subscribe(() => this._updateViewportSize()); + }); } ngOnDestroy() {