fix(core): detectChanges() doesn't work on detached instance

Closes #13426
Closes #13472
This commit is contained in:
Miško Hevery 2016-12-13 16:26:22 -08:00 committed by Victor Berchet
parent b56474d067
commit a659259962
3 changed files with 34 additions and 3 deletions

View File

@ -576,7 +576,7 @@ function generateDetectChangesMethod(view: CompileView): o.Statement[] {
} }
stmts.push(...view.detectChangesRenderPropertiesMethod.finish()); stmts.push(...view.detectChangesRenderPropertiesMethod.finish());
view.viewChildren.forEach((viewChild) => { view.viewChildren.forEach((viewChild) => {
stmts.push(viewChild.callMethod('detectChanges', [DetectChangesVars.throwOnChange]).toStmt()); stmts.push(viewChild.callMethod('internalDetectChanges', [DetectChangesVars.throwOnChange]).toStmt());
}); });
const afterViewStmts = const afterViewStmts =
view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish()); view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish());

View File

@ -312,11 +312,16 @@ export abstract class AppView<T> {
*/ */
dirtyParentQueriesInternal(): void {} dirtyParentQueriesInternal(): void {}
internalDetectChanges(throwOnChange: boolean): void {
if (this.cdMode !== ChangeDetectorStatus.Detached) {
this.detectChanges(throwOnChange);
}
}
detectChanges(throwOnChange: boolean): void { detectChanges(throwOnChange: boolean): void {
const s = _scope_check(this.clazz); const s = _scope_check(this.clazz);
if (this.cdMode === ChangeDetectorStatus.Checked || if (this.cdMode === ChangeDetectorStatus.Checked ||
this.cdMode === ChangeDetectorStatus.Errored || this.cdMode === ChangeDetectorStatus.Errored)
this.cdMode === ChangeDetectorStatus.Detached)
return; return;
if (this.cdMode === ChangeDetectorStatus.Destroyed) { if (this.cdMode === ChangeDetectorStatus.Destroyed) {
this.throwDestroyedError('detectChanges'); this.throwDestroyedError('detectChanges');

View File

@ -82,6 +82,7 @@ export function main() {
AnotherComponent, AnotherComponent,
TestLocals, TestLocals,
CompWithRef, CompWithRef,
WrapCompWithRef,
EmitterDirective, EmitterDirective,
PushComp, PushComp,
OnDestroyDirective, OnDestroyDirective,
@ -1133,6 +1134,23 @@ export function main() {
expect(renderLog.log).toEqual([]); expect(renderLog.log).toEqual([]);
})); }));
it('Detached view can be checked locally', fakeAsync(() => {
const ctx = createCompFixture('<wrap-comp-with-ref></wrap-comp-with-ref>');
const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0];
cmp.value = 'hello';
cmp.changeDetectorRef.detach();
expect(renderLog.log).toEqual([]);
ctx.detectChanges();
expect(renderLog.log).toEqual([]);
cmp.changeDetectorRef.detectChanges();
expect(renderLog.log).toEqual(['{{hello}}']);
}));
it('Reattaches', fakeAsync(() => { it('Reattaches', fakeAsync(() => {
const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); const ctx = createCompFixture('<comp-with-ref></comp-with-ref>');
const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0];
@ -1346,6 +1364,14 @@ class CompWithRef {
noop() {} noop() {}
} }
@Component({
selector: 'wrap-comp-with-ref',
template: '<comp-with-ref></comp-with-ref>'
})
class WrapCompWithRef {
constructor(public changeDetectorRef: ChangeDetectorRef) {}
}
@Component({ @Component({
selector: 'push-cmp', selector: 'push-cmp',
template: '<div (event)="noop()" emitterDirective></div>{{value}}{{renderIncrement}}', template: '<div (event)="noop()" emitterDirective></div>{{value}}{{renderIncrement}}',