Dynamic classname inside ngClass in angular 2

Angular

Angular Problem Overview


I need to interpolate a value inside of an ngClass expression but I can't get it to work.

I tried these solution which are the only ones that makes sense to me, these two fails with the interpolation:

<button [ngClass]="{'{{namespace}}-mybutton': type === 'mybutton'}"></button>
<button [ngClass]="{namespace + '-mybutton': type === 'mybutton'}"></button>

This one works with the interpolation but fails with the dynamically added class because the entire string gets added as a class:

<button ngClass="{'{{namespace}}-mybutton': type === 'mybutton'}"></button>

So my question is how do you use dynamic classnames in ngClass like this?

Angular Solutions


Solution 1 - Angular

Try

<button [ngClass]="type === 'mybutton' ? namespace + '-mybutton' : ''"></button>

instead.

or

<button [ngClass]="[type === 'mybutton' ? namespace + '-mybutton' : '']"></button>

or even

<button class="{{type === 'mybutton' ? namespace + '-mybutton' : ''}}"></button>

will work but extra benefit of using ngClass is that it does not overwrite other classes that are added by any other method( eg: [class.xyz] directive or class attribute, etc.) as class does.

Angular 9 Update

The new compiler, Ivy, brings more clarity and predictability to what happens when there are different types of class-bindings on the same element. Read More about it here.


ngClass takes three types of input

  • Object: each key corresponds to a CSS class name, you can't have dynamic keys, because key 'key' "key" are all same, and [key] is not supported AFAIK.

  • Array: can only contain list of classes, no conditions, although ternary operator works

  • String/ expression: just like normal class attribute

Solution 2 - Angular

This one should work

<button [ngClass]="{[namespace + '-mybutton']: type === 'mybutton'}"></button>

but Angular throws on this syntax. I'd consider this a bug. See also https://stackoverflow.com/a/36024066/217408

The others are invalid. You can't use [] together with {{}}. Either one or the other. {{}} binds the result stringified which doesn't lead to the desired result in this case because an object needs to be passed to ngClass.

Plunker example

As workaround the syntax shown by @A_Sing or

<button [ngClass]="type === 'mybutton' ? namespace + '-mybutton' : ''"></button>

can be used.

Solution 3 - Angular

  <div *ngFor="let celeb of singers">
  <p [ngClass]="{
    'text-success':celeb.country === 'USA',
    'text-secondary':celeb.country === 'Canada',
    'text-danger':celeb.country === 'Puorto Rico',
    'text-info':celeb.country === 'India'
  }">{{ celeb.artist }} ({{ celeb.country }})
</p>
</div>

Solution 4 - Angular

Is basically duplication of the other answers - but I didn't get it completely. maybe someone will finally understand it with this example now.

[ngClass]="['svg-icon', 'recolor-' + recolor, size ? 'size-' + size : '']"

will result for e.g. in

class="svg-icon recolor-red size-m"

Solution 5 - Angular

i want to mention some important point to bare in mind while implementing class binding.

    [ngClass] = "{
    'badge-secondary': somevariable  === value1,
    'badge-danger': somevariable  === value1,
    'badge-warning': somevariable  === value1,
    'badge-warning': somevariable  === value1,
    'badge-success': somevariable  === value1 }" 

class here is not binding correctly because one condition is to be met, whereas you have two identical classes 'badge-warning' that may have two different condition. To correct this

 [ngClass] = "{
    'badge-secondary': somevariable === value1,
    'badge-danger': somevariable  === value1,
    'badge-warning': somevariable  === value1 || somevariable  === value1, 
    'badge-success': somevariable  === value1 }" 

Solution 6 - Angular

This works perfectly!

<div [class.any-class]="condition"></div>

Example:

<div [class.hide]="user.isPaid()"></div>

Solution 7 - Angular

The easiest way might be to define a getter in your component.ts. Most importantly, it's one of the recommendations in Angular coding style

// in your component.ts
get buttonClasses() {
    return { [`${this.namespace}-mybutton`]: this.type === 'mybutton' }
}
<!-- in your component.html -->
<button [ngClass]="buttonClasses"></button>

Solution 8 - Angular

Here's an example of something I'm doing for multiple classes with multiple conditions:

[ngClass]="[variableInComponent || !anotherVariableInComponent ? classes.icon.large : classes.icon.small, editing ? classes.icon.editing : '']"

where:
classes is an object containing strings of various classnames. e.g. class.icon.large = "app__icon--large"

It's dynamic! Updates as the conditions update.

Solution 9 - Angular

You can use <i [className]="'fa fa-' + data?.icon"> </i>

Solution 10 - Angular

more elegant solution is to use && (using NgFor and its first, its free to use ur own matching tho):

    <div 
        *ngFor="let day of days;
                let first = first;"
        class="day"
        [ngClass]="first && ('day--' + day)"
    </div>

will turn out as:

class="day day--monday"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChrillewoodzView Question on Stackoverflow
Solution 1 - AngularAnkit SinghView Answer on Stackoverflow
Solution 2 - AngularGünter ZöchbauerView Answer on Stackoverflow
Solution 3 - AngularSHUBHASIS MAHATAView Answer on Stackoverflow
Solution 4 - Angularperform3rView Answer on Stackoverflow
Solution 5 - AngularDicekeyView Answer on Stackoverflow
Solution 6 - AngularKroksysView Answer on Stackoverflow
Solution 7 - AngularMamadou OuologuemView Answer on Stackoverflow
Solution 8 - AngularykadaruView Answer on Stackoverflow
Solution 9 - AngularAnthony AgbatorView Answer on Stackoverflow
Solution 10 - AngularDen KernyView Answer on Stackoverflow