54

I want to dynamically add a css class to an <li> element I am looping over. The loop is like this:

<li ng-repeat="todo in todos" ng-class="{{todo.priority}}">
  <a href="#/todos/{{todo.id}}">{{todo.title}}</a>
  <p>{{todo.description}}</p>
</li>

In my todo model, I have the property priority which can be "urgent", "not-so-important" or "normal" and I just want to assign the class for each element.

I know I can do this for a boolean with something like ng-class="{'urgent': todo.urgent}" But my variable is not a boolean, but has three values. How would I do this? Note also that I do not want to use ng-style="..." since my class will alter several visual things.

mpaepper
  • 3,952
  • 3
  • 21
  • 28

4 Answers4

94

You can simply assign a function as an expression and return proper class from there. Edit: there is also better solution for dynamic classes. Please see note below.

Snippet from view:

<div ng-class="appliedClass(myObj)">...</div>

and in the controller:

$scope.appliedClass = function(myObj) {
    if (myObj.someValue === "highPriority") {
        return "special-css-class";
    } else {
        return "default-class"; // Or even "", which won't add any additional classes to the element
    }
}

Better way of doing this

I've recently learned about another approach. You pass in an object which has properties corresponding to the classes you operate on, and the values are expressions or boolean variables. A simple example:

ng-class="{ active: user.id == activeId }"

In this case active class will be added to the element as long as user.id matches activeId from the $scope object!

ŁukaszBachman
  • 33,595
  • 11
  • 64
  • 74
  • 7
    More accurately, `ng-class` takes either an object or a string, so you can do `ng-class=" 'myClass'+item.priority "` – ProLoser Mar 21 '13 at 05:08
  • I'm an angular noob, but I think there's another good reason to use the latter method rather than the former - I think if you use a function it might not set up the proper watches, whereas if you use the attributes directly it should do so. – Ibrahim Sep 11 '13 at 02:53
  • 1
    i was already using your second method but then ran into a wall (basically the second method isn't very useful when you have multiple/complex ways of deriving the class that should be placed.. ie stuff that demands more than simple if statement).. so +1 on method 1 – abbood Jul 17 '14 at 07:46
  • this is very useful for me http://tech-blog.maddyzone.com/javascript/conditionally-apply-classes-in-angularjs – Rituraj ratan Sep 06 '14 at 04:39
  • 1
    There´s an 'else' option? Don´t wanna do { active: user.id == activeId } {inactive: user.id != activeId}... – dipi evil Apr 22 '15 at 20:21
  • @dipievil why would you want to have "else" option? You simply write two rules in CSS, where `active` overwrites the other. For instance: `a { color: black; }` and `a.active { color: red; }` – ŁukaszBachman Apr 24 '15 at 05:53
  • I know I have other ways to do it. I was just wondering. Tanks anyway. ;) – dipi evil Apr 24 '15 at 13:14
  • I was wondering if it was possible to have an "else" option. I mean, I know I can write two CSS rules, but even knowing that, I want to know if the "else" option exists :) – Mauker May 27 '15 at 15:15
  • As far as I'm aware there is no `else` option available. That is because in CSS you mock this `if-else` condition by having the `default-overwritten` rules. – ŁukaszBachman May 27 '15 at 19:33
  • @dipievil, `ng-class="user.id == activeId ? 'active' : 'inactive'"` – primetwig Sep 17 '15 at 13:30
  • This only works for a static list of known classes. If your classes are actually dynamic (in the sense that you don't know what the class string might be) then you can't use this method. Which is annoying. – geoidesic Feb 22 '17 at 15:40
  • 1
    @geoidesic, that's not true. The original solution `ng-class="appliedClass(myObj)"` generates classes dynamically based on `myObj` state. – ŁukaszBachman Mar 30 '17 at 06:04
44

If you just want to add a class, use the class attribute with interpolation:

class="priority-is-{{todo.priority}}"
Gilbert
  • 3,584
  • 2
  • 26
  • 30
10

You almost got it :)
It should be without interpolation markup ({{ and }}):

<li ng-repeat="todo in todos" ng-class="todo.priority">
...
vucalur
  • 6,007
  • 3
  • 29
  • 46
0

You can do this dynamically and with a ternary.

ng-class="service.Icon != '' ? service.Icon : 'fas fa-arrow-alt-circle-right'"

The above code will inject the class stored in Icon if it is not null and default to the second if you its not included.

This will allow for multiple classes.

The answer above where you call a function() in databound instances may cause a document consumption loop if anything in the state changes. If you were to put a console write in that, you may find your page is rendered 100 times before it stops looping.

NOTE: Don't put the object {} around it when using ternary. You will get errors.

Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62