diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 555a5a1f93..f65583b0e2 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -2751,7 +2751,7 @@ function tickRootContext(rootContext: RootContext) { * @param component The component which the change detection should be performed on. */ export function detectChanges(component: T): void { - const view = getComponentViewByInstance(component) !; + const view = getComponentViewByInstance(component); detectChangesInternal(view, component); } @@ -2790,9 +2790,14 @@ export function detectChangesInRootView(lView: LView): void { * introduce other changes. */ export function checkNoChanges(component: T): void { + const view = getComponentViewByInstance(component); + checkNoChangesInternal(view, component); +} + +export function checkNoChangesInternal(view: LView, context: T) { setCheckNoChangesMode(true); try { - detectChanges(component); + detectChangesInternal(view, context); } finally { setCheckNoChangesMode(false); } diff --git a/packages/core/src/render3/view_ref.ts b/packages/core/src/render3/view_ref.ts index 46e7c7a525..9130e87385 100644 --- a/packages/core/src/render3/view_ref.ts +++ b/packages/core/src/render3/view_ref.ts @@ -11,9 +11,9 @@ import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detec import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref'; -import {checkNoChanges, checkNoChangesInRootView, checkView, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn, viewAttached} from './instructions'; +import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn} from './instructions'; import {TNode, TNodeType, TViewNode} from './interfaces/node'; -import {FLAGS, HOST, LView, LViewFlags, PARENT, RENDERER_FACTORY, T_HOST} from './interfaces/view'; +import {FLAGS, HOST, LView, LViewFlags, PARENT, T_HOST} from './interfaces/view'; import {destroyLView} from './node_manipulation'; import {getNativeByTNode} from './util'; @@ -252,7 +252,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * This is used in development mode to verify that running change detection doesn't * introduce other changes. */ - checkNoChanges(): void { checkNoChanges(this.context); } + checkNoChanges(): void { checkNoChangesInternal(this._lView, this.context); } attachToViewContainerRef(vcRef: viewEngine_ViewContainerRef) { if (this._appRef) { diff --git a/packages/core/test/acceptance/change_detection_spec.ts b/packages/core/test/acceptance/change_detection_spec.ts new file mode 100644 index 0000000000..8978ca4b17 --- /dev/null +++ b/packages/core/test/acceptance/change_detection_spec.ts @@ -0,0 +1,71 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + +import {ApplicationRef, Component, Directive, EmbeddedViewRef, TemplateRef, ViewContainerRef} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +describe('change detection', () => { + + describe('embedded views', () => { + + @Directive({selector: '[viewManipulation]', exportAs: 'vm'}) + class ViewManipulation { + constructor( + private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef, + private _appRef: ApplicationRef) {} + + insertIntoVcRef() { this._vcRef.createEmbeddedView(this._tplRef); } + + insertIntoAppRef(): EmbeddedViewRef<{}> { + const viewRef = this._tplRef.createEmbeddedView({}); + this._appRef.attachView(viewRef); + return viewRef; + } + } + + @Component({ + selector: 'test-cmp', + template: ` + {{'change-detected'}} + ` + }) + class TestCmpt { + } + + beforeEach(() => { + TestBed.configureTestingModule({declarations: [TestCmpt, ViewManipulation]}); + }); + + it('should detect changes for embedded views inserted through ViewContainerRef', () => { + const fixture = TestBed.createComponent(TestCmpt); + const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; + + vm.insertIntoVcRef(); + fixture.detectChanges(); + + expect(fixture.nativeElement).toHaveText('change-detected'); + }); + + it('should detect changes for embedded views attached to ApplicationRef', () => { + const fixture = TestBed.createComponent(TestCmpt); + const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; + + const viewRef = vm.insertIntoAppRef(); + + // A newly created view was attached to the CD tree via ApplicationRef so should be also + // change detected when ticking root component + fixture.detectChanges(); + + expect(viewRef.rootNodes[0]).toHaveText('change-detected'); + }); + + }); + +}); \ No newline at end of file diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index c17f77c60f..65fb980ad8 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -426,7 +426,7 @@ "name": "callHooks" }, { - "name": "checkNoChanges" + "name": "checkNoChangesInternal" }, { "name": "checkNoChangesMode" @@ -527,9 +527,6 @@ { "name": "detachView" }, - { - "name": "detectChanges" - }, { "name": "detectChangesInternal" },