fix(ivy): ensure errors are thrown during checkNoChanges for style/class bindings (#33103)

Prior to this fix, all style/class bindings (e.g. `[style]` and
`[class.foo]`) would quietly update a binding value if and when the
current binding value changes during checkNoChanges.

With this patch, all styling instructions will properly check to see
if the value has changed during the second pass of detectChanges()
if checkNoChanges is active.

PR Close #33103
This commit is contained in:
Matias Niemelä
2019-10-11 17:31:26 +02:00
parent 9d54679e66
commit f45c43188f
8 changed files with 116 additions and 37 deletions

View File

@ -2241,6 +2241,57 @@ describe('styling', () => {
fixture.detectChanges();
expect(div.classList.contains('disabled')).toBe(false);
});
it('should throw an error if a prop-based style/class binding value is changed during checkNoChanges',
() => {
@Component({
template: `
<div [style.color]="color" [class.foo]="fooClass"></div>
`
})
class Cmp {
color = 'red';
fooClass = true;
ngAfterViewInit() {
this.color = 'blue';
this.fooClass = false;
}
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
expect(() => {
fixture.detectChanges();
}).toThrowError(/ExpressionChangedAfterItHasBeenCheckedError/);
});
onlyInIvy('only ivy allows for map-based style AND class bindings')
.it('should throw an error if a map-based style/class binding value is changed during checkNoChanges',
() => {
@Component({
template: `
<div [style]="style" [class]="klass"></div>
`
})
class Cmp {
style: any = {width: '100px'};
klass: any = {foo: true, bar: false};
ngAfterViewInit() {
this.style = {height: '200px'};
this.klass = {foo: false};
}
}
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
expect(() => {
fixture.detectChanges();
}).toThrowError(/ExpressionChangedAfterItHasBeenCheckedError/);
});
});
function assertStyleCounters(countForSet: number, countForRemove: number) {