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.
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._
Most helpful comment
I tracked down the root cause:
NgControlGroup
declares anonInit
method, which schedules some work to be completed asynchronously, viaPromiseWrapper.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 afteronInit
is called,AbstractChangeDetector.alreadyChecked
will not be set andonInit
will be run again during the next tick. SinceonInit
inNgControlGroup
schedules asynchronous work, that next tick will happen immediately, causing a crash loop.