diff --git a/modules/angular2/src/core/life_cycle/life_cycle.ts b/modules/angular2/src/core/life_cycle/life_cycle.ts index f432bd3961..5a9e218367 100644 --- a/modules/angular2/src/core/life_cycle/life_cycle.ts +++ b/modules/angular2/src/core/life_cycle/life_cycle.ts @@ -2,7 +2,7 @@ import {Injectable} from 'angular2/di'; import {ChangeDetector} from 'angular2/change_detection'; import {NgZone} from 'angular2/src/core/zone/ng_zone'; import {ExceptionHandler} from 'angular2/src/core/exception_handler'; -import {isPresent} from 'angular2/src/facade/lang'; +import {isPresent, BaseException} from 'angular2/src/facade/lang'; /** * Provides access to explicitly trigger change detection in an application. @@ -36,6 +36,7 @@ export class LifeCycle { _errorHandler; _changeDetector: ChangeDetector; _enforceNoNewChanges: boolean; + _runningTick: boolean = false; constructor(exceptionHandler: ExceptionHandler, changeDetector: ChangeDetector = null, enforceNoNewChanges: boolean = false) { @@ -75,9 +76,18 @@ export class LifeCycle { * */ tick() { - this._changeDetector.detectChanges(); - if (this._enforceNoNewChanges) { - this._changeDetector.checkNoChanges(); + if (this._runningTick) { + throw new BaseException("LifeCycle.tick is called recursively"); + } + + try { + this._runningTick = true; + this._changeDetector.detectChanges(); + if (this._enforceNoNewChanges) { + this._changeDetector.checkNoChanges(); + } + } finally { + this._runningTick = false; } } } diff --git a/modules/angular2/test/core/life_cycle/life_cycle_spec.ts b/modules/angular2/test/core/life_cycle/life_cycle_spec.ts new file mode 100644 index 0000000000..98a48d2552 --- /dev/null +++ b/modules/angular2/test/core/life_cycle/life_cycle_spec.ts @@ -0,0 +1,38 @@ +import { + ddescribe, + describe, + it, + iit, + xit, + expect, + beforeEach, + afterEach, + el, + AsyncTestCompleter, + fakeAsync, + tick, + SpyObject, + inject, + proxy + } from 'angular2/test_lib'; +import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; +import {ChangeDetector} from 'angular2/change_detection'; +import {IMPLEMENTS} from 'angular2/src/facade/lang'; + +@proxy +@IMPLEMENTS(ChangeDetector) +class SpyChangeDetector extends SpyObject { + constructor() { super(ChangeDetector); } + noSuchMethod(m) { return super.noSuchMethod(m) } +} + +export function main() { + describe("LifeCycle", () => { + it("should throw when reentering tick", () => { + var cd = new SpyChangeDetector(); + var lc = new LifeCycle(null, cd, false); + cd.spy("detectChanges").andCallFake(() => lc.tick()); + expect(() => lc.tick()).toThrowError("LifeCycle.tick is called recursively"); + }); + }); +}