Reputation: 291
In the Angular2 documentation on template syntax the sample code for the preferred method for setting multiple styles at the same time is this:
setStyles() {
let styles = {
// CSS property names
'font-style': this.canSave ? 'italic' : 'normal', // italic
'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal
'font-size': this.isSpecial ? 'x-large': 'smaller', // larger
}
return styles;
}
Called like this:
<div [ngStyle]="setStyles()">
This div is italic, normal weight, and x-large
</div>
However, trying out this code in the Tour of Heroes project causes the following error:
Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.
EXCEPTION: Error during evaluation of "click"
EXCEPTION: Expression 'setClasses() in AppComponent@11:10' has changed after it was checked.
Previous value: '[object Object]'. Current value: '[object Object]' in [setClasses() in AppComponent@11:10]
I understand this is part of Angular2’s drive to emphasise unidirectional data flow, but given this example as a best practice, what’s going on?
I found one suggested solution to this issue here, which has no accepted answer. The discussion takeaway: Anything that changes a binding needs to trigger a round of change detection when it does. In the notes there was a link to another answer which said this: manually run change detection:
Use ApplicationRef::tick() method.
Use NgZone::run() method to wrap you code which should be executed inside angular zone.
Trying to then use the method app.tick();
and NgZone::run()
both break the entire application, or I’m just using it wrong.
I have created this Plunker to demonstrate this issue. When you select a hero, the styles on their name should change depending on the data they have available in their model. For example, the first five heroes have a standard style, but the next three, Dr IQ, SkyDog and J-Dragon have alter egos and powers. In development mode, you can only select one and the app breaks with the message: Expression 'setClasses() in AppComponent@11:10' has changed after it was checked.
If you un-comment out the //enableProdMode(); in boot.ts, then the app works fine.
So what’s up with that? I want to be able to use development mode and use ngClass in this way. What is the best practice for doing this?
Upvotes: 2
Views: 1106
Reputation: 5344
Change:
<h4 [ngClass]="setClasses()">
for:
<h4 [ngClass]="classes">
and call the setClasses method in the onSelect
method:
onSelect(hero: Hero) {
this.selectedHero = hero;
hero.power ? this.stylar1 = true: this.stylar1 = false;
hero.alterEgo ? this.stylar2 = true: this.stylar2 = false;
this.setClasses();
}
http://plnkr.co/edit/95H4YNtdfn3y2KTdX8Xu?p=preview
Upvotes: 1