Angular: Change detection error -> infinite loop

Created on 23 Sep 2015  ·  3Comments  ·  Source: angular/angular

I found a case where change detection enters an infinite loop on an error.

The code in question:

@Component({selector: "signup-comp"})
@View({
  directives: [CORE_DIRECTIVES, FORM_DIRECTIVES],
  template: `
    <form #f="form" (ng-submit)='onSignUp(f.value)'>
      <div ng-control-group='credentials' #credentials="form">
        Login <input type='text' ng-control='login'>
        Password <input type='password' ng-control='password'>
      </div>
      <div *ng-if="!d.valid">Credentials are invalid</div>
      <div ng-control-group='personal'>
        Name <input type='text' ng-control='name'>
      </div>
      <button type='submit'>Sign Up!</button>
    </form>
  `
})

The key is the ng-if expression !d.valid. d is not defined, and this triggers an infinite loop.

Here is a full Plunker example.

hours bufix

Most helpful comment

I tracked down the root cause:

NgControlGroup declares an onInit method, which schedules some work to be completed asynchronously, via PromiseWrapper.resolve.

The problem is that onInit can actually be called multiple times - it is called if change detection runs and has never completed successfully. If an exception happens during change detection after onInit is called, AbstractChangeDetector.alreadyChecked will not be set and onInit will be run again during the next tick. Since onInit in NgControlGroup schedules asynchronous work, that next tick will happen immediately, causing a crash loop.

All 3 comments

It seems like <div ng-control-group='credentials'></div> combined with the ng-if is enough to trigger the bug.

I tracked down the root cause:

NgControlGroup declares an onInit method, which schedules some work to be completed asynchronously, via PromiseWrapper.resolve.

The problem is that onInit can actually be called multiple times - it is called if change detection runs and has never completed successfully. If an exception happens during change detection after onInit is called, AbstractChangeDetector.alreadyChecked will not be set and onInit will be run again during the next tick. Since onInit in NgControlGroup schedules asynchronous work, that next tick will happen immediately, causing a crash loop.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings