feat(core): @Volatile() decorator to allow unstable properties for change detection
See original GitHub issueI’m submitting a …
[ ] Regression (behavior that used to work and stopped working in a new release)
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
In dev mode, Angular will have additional change detection to make sure all properties not being changed after first change detection.
For example, when we have a getter to call Map#keys()
, it would throw ExpressionChangedAfterItHasBeenCheckedError
since it returns a new Iterator
each time:
@Component({
template: `
<ul>
<li *ngFor="let key of keys">{{ key }}</li>
</ul>
`,
})
export class App {
private map: Map<number>
constructor() {
this.map = new Map([
['a', 1],
['b', 2],
['c', 3],
])
}
get keys() {
return this.map.keys()
}
}
A live example could be found here.
Expected behavior
Since we know that the new iterator is equal to the old one in semantics, we can tell Angular to ignore its (and its sub-properties’) change by adding an @Volatile()
decorator to the property:
@Component({
template: `
<ul>
<li *ngFor="let key of keys">{{ key }}</li>
</ul>
`,
})
export class App {
private map: Map<number>
constructor() {
this.map = new Map([
['a', 1],
['b', 2],
['c', 3],
])
}
@Volatile()
get keys() {
return this.map.keys()
}
}
And no error would be thrown.
Minimal reproduction of the problem with instructions
https://plnkr.co/edit/E5kvFLWNEjN3NVfur7HL?p=preview
What is the motivation / use case for changing the behavior?
This would help with getter-style implementations and some low-level operations.
Relates to:
https://github.com/angular/angular/issues/2246 https://github.com/angular/angular/issues/15464 https://github.com/angular/angular/issues/15721 https://github.com/angular/angular/issues/16049 https://github.com/angular/angular/issues/17070 https://github.com/angular/angular/issues/17347 https://github.com/angular/angular/issues/17572 https://github.com/angular/angular/issues/17724
Alternatives:
- Introduce a
volatile
property in Component Metadata to disable the second-time checking at Component level.
Please tell us about your environment
Angular version: not relevant
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: not relevant
- Platform: not relevant
Others: none
Issue Analytics
- State:
- Created 6 years ago
- Reactions:3
- Comments:11 (5 by maintainers)
@trotyl no setter needed, just:
@ChinesePeanuts That is a valid workaround, but just a workaround. No one came to Angular to find out how many workarounds there are, and that’s something should not be addicted to.
The proposal here is to get rid of those workarounds in achieving something that already works.