diff --git a/packages/core/src/render3/after_render_hooks.ts b/packages/core/src/render3/after_render_hooks.ts index c583fe9d6f4..6a13c4d57bf 100644 --- a/packages/core/src/render3/after_render_hooks.ts +++ b/packages/core/src/render3/after_render_hooks.ts @@ -10,6 +10,7 @@ import {assertInInjectionContext, Injector, ɵɵdefineInjectable} from '../di'; import {inject} from '../di/injector_compatibility'; import {RuntimeError, RuntimeErrorCode} from '../errors'; import {DestroyRef} from '../linker/destroy_ref'; +import {NgZone} from '../zone'; import {isPlatformBrowser} from './util/misc_utils'; @@ -91,7 +92,8 @@ export function afterRender(callback: VoidFunction, options?: AfterRenderOptions let destroy: VoidFunction|undefined; const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.()); const manager = injector.get(AfterRenderEventManager); - const instance = new AfterRenderCallback(callback); + const ngZone = injector.get(NgZone); + const instance = new AfterRenderCallback(() => ngZone.runOutsideAngular(callback)); destroy = () => { manager.unregister(instance); @@ -155,9 +157,10 @@ export function afterNextRender( let destroy: VoidFunction|undefined; const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.()); const manager = injector.get(AfterRenderEventManager); + const ngZone = injector.get(NgZone); const instance = new AfterRenderCallback(() => { destroy?.(); - callback(); + ngZone.runOutsideAngular(callback); }); destroy = () => { diff --git a/packages/core/test/acceptance/after_render_hook_spec.ts b/packages/core/test/acceptance/after_render_hook_spec.ts index 5e3e6b97619..eeb7fcf4099 100644 --- a/packages/core/test/acceptance/after_render_hook_spec.ts +++ b/packages/core/test/acceptance/after_render_hook_spec.ts @@ -7,7 +7,7 @@ */ import {PLATFORM_BROWSER_ID, PLATFORM_SERVER_ID} from '@angular/common/src/platform_id'; -import {afterNextRender, afterRender, AfterRenderRef, ChangeDetectorRef, Component, inject, Injector, PLATFORM_ID, ViewContainerRef} from '@angular/core'; +import {afterNextRender, afterRender, AfterRenderRef, ChangeDetectorRef, Component, inject, Injector, NgZone, PLATFORM_ID, ViewContainerRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; describe('after render hooks', () => { @@ -225,6 +225,29 @@ describe('after render hooks', () => { expect(outerHookCount).toBe(3); expect(innerHookCount).toBe(2); }); + + it('should run outside of the Angular zone', () => { + const zoneLog: boolean[] = []; + + @Component({selector: 'comp'}) + class Comp { + constructor() { + afterRender(() => { + zoneLog.push(NgZone.isInAngularZone()); + }); + } + } + + TestBed.configureTestingModule({ + declarations: [Comp], + ...COMMON_CONFIGURATION, + }); + const fixture = TestBed.createComponent(Comp); + + expect(zoneLog).toEqual([]); + fixture.detectChanges(); + expect(zoneLog).toEqual([false]); + }); }); describe('afterNextRender', () => { @@ -431,6 +454,29 @@ describe('after render hooks', () => { expect(outerHookCount).toBe(1); expect(innerHookCount).toBe(1); }); + + it('should run outside of the Angular zone', () => { + const zoneLog: boolean[] = []; + + @Component({selector: 'comp'}) + class Comp { + constructor() { + afterNextRender(() => { + zoneLog.push(NgZone.isInAngularZone()); + }); + } + } + + TestBed.configureTestingModule({ + declarations: [Comp], + ...COMMON_CONFIGURATION, + }); + const fixture = TestBed.createComponent(Comp); + + expect(zoneLog).toEqual([]); + fixture.detectChanges(); + expect(zoneLog).toEqual([false]); + }); }); }); diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index d0077f6904f..1a6adf97acc 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -1980,7 +1980,7 @@ "name": "tap" }, { - "name": "throwError5" + "name": "throwError2" }, { "name": "throwIfEmpty"