diff --git a/modules/@angular/core/src/change_detection/change_detection_util.ts b/modules/@angular/core/src/change_detection/change_detection_util.ts index 1b5af4cf51..cd9b6c852f 100644 --- a/modules/@angular/core/src/change_detection/change_detection_util.ts +++ b/modules/@angular/core/src/change_detection/change_detection_util.ts @@ -11,7 +11,9 @@ import {isPrimitive, looseIdentical} from '../facade/lang'; export {looseIdentical} from '../facade/lang'; -export const UNINITIALIZED = new Object(); +export const UNINITIALIZED = { + toString: () => 'CD_INIT_VALUE' +}; export function devModeEqual(a: any, b: any): boolean { if (isListLikeIterable(a) && isListLikeIterable(b)) { diff --git a/modules/@angular/core/src/linker/exceptions.ts b/modules/@angular/core/src/linker/exceptions.ts index 36d84b2688..049af39779 100644 --- a/modules/@angular/core/src/linker/exceptions.ts +++ b/modules/@angular/core/src/linker/exceptions.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import {UNINITIALIZED} from '../change_detection/change_detection_util'; import {BaseException, WrappedException} from '../facade/exceptions'; + /** * An error thrown if application changes model breaking the top-down data flow. * @@ -44,9 +46,14 @@ import {BaseException, WrappedException} from '../facade/exceptions'; */ export class ExpressionChangedAfterItHasBeenCheckedException extends BaseException { constructor(oldValue: any, currValue: any, context: any) { - super( - `Expression has changed after it was checked. ` + - `Previous value: '${oldValue}'. Current value: '${currValue}'`); + let msg = + `Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`; + if (oldValue === UNINITIALIZED) { + msg += + ` It seems like the view has been created after its parent and its children have been dirty checked.` + + ` Has it been created in a change detection hook ?`; + } + super(msg); } } diff --git a/modules/@angular/core/test/linker/change_detection_integration_spec.ts b/modules/@angular/core/test/linker/change_detection_integration_spec.ts index d8f2524d95..987e666c95 100644 --- a/modules/@angular/core/test/linker/change_detection_integration_spec.ts +++ b/modules/@angular/core/test/linker/change_detection_integration_spec.ts @@ -1002,15 +1002,22 @@ export function main() { describe('enforce no new changes', () => { it('should throw when a record gets changed after it has been checked', fakeAsync(() => { - var ctx = createCompFixture('
', TestData); - + const ctx = createCompFixture('', TestData); ctx.componentInstance.a = 1; expect(() => ctx.checkNoChanges()) .toThrowError(/:0:5[\s\S]*Expression has changed after it was checked./g); })); + it('should warn when the view has been created in a cd hook', fakeAsync(() => { + const ctx = createCompFixture('