1204

Lets say you have an array that is rendered in a ul with an li for each element and a property on the controller called selectedIndex. What would be the best way to add a class to the li with the index selectedIndex in AngularJS?

I am currently duplicating (by hand) the li code and adding the class to one of the li tags and using ng-show and ng-hide to show only one li per index.

Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
respectTheCode
  • 42,348
  • 18
  • 73
  • 86
  • 2
    Answers to this question show that there is more to the templating than {{varname}}. Where can I find documentation of what more there is to templating, such as the ternary operator in a couple of different forms? http://docs.angularjs.org/guide/templates does not seem to explain what templating offers in terms of conditionals etc. besides {{varname.fieldname}}. – Christos Hayward Feb 21 '14 at 18:35
  • this is so mush useful for me hope it will work for you http://tech-blog.maddyzone.com/javascript/conditionally-apply-classes-in-angularjs – Rituraj ratan Sep 06 '14 at 04:38

23 Answers23

1386

If you don't want to put CSS class names into Controller like I do, here is an old trick that I use since pre-v1 days. We can write an expression that evaluates directly to a class name selected, no custom directives are necessary:

ng:class="{true:'selected', false:''}[$index==selectedIndex]"

Please note the old syntax with colon.

There is also a new better way of applying classes conditionally, like:

ng-class="{selected: $index==selectedIndex}"

Angular now supports expressions that return an object. Each property (name) of this object is now considered as a class name and is applied depending on its value.

However these ways are not functionally equal. Here is an example:

ng-class="{admin:'enabled', moderator:'disabled', '':'hidden'}[user.role]"

We could therefore reuse existing CSS classes by basically mapping a model property to a class name and at the same time keep CSS classes out of Controller code.

orcun
  • 14,969
  • 1
  • 22
  • 25
  • This doesn't remove the old class in v0.10 but it seems to work in v0.9.x – respectTheCode Feb 09 '12 at 12:56
  • @respectTheCode Hmm, I havent't had the opportunity to test v0.10 Have to reported an issue? – orcun Feb 10 '12 at 14:55
  • 33
    OP, that may be the worse way to express the ternary operator I've ever seen. Have you considered `($index==selectedIndex) ? 'selected' : ''` ? – Michael Lorton May 07 '12 at 22:07
  • 17
    @Malvolio AFAIR, ternary operator was not working within angular expressions in v0.9.x . This is more or less a switch. – orcun May 08 '12 at 09:25
  • 36
    ng-class (as of 1/19/2012) now supports an expression that must evaluate to either 1) a string of space-delimited class names, or 2) and array of class names, or 3) a map/object of class names to boolean values. So, using 3): ng-class="{selected: $index==selectedIndex}" – Mark Rajcok Aug 28 '12 at 01:11
  • 2
    Thanks @Mark, BTW now that I have checked I can say that this method is working in v1. It still useful in some cases. Note that object property names(keys) are not necessarily true or false, it can be anything that you might wanna map to a class name. – orcun Aug 29 '12 at 18:49
  • 6
    I just want to add, I was having an issue because I was using syntax like `{classname: '$index === selectedIndex'}` and it wasn't working. When I pushed everything together and used == instead of === it worked. `{classname: '$index==selectedIndex'}` – Lucas Feb 13 '13 at 23:16
  • How can I use an expression for the classname too? For example ng-class="{'item-focus-'+focusIndex : focusIndex >= 0}" -- this does not work, but illustrates what I have in mind – Casey Feb 20 '13 at 08:04
  • @Casey Unfortunately not all javascript expressions are valid angularjs expressions. Perhaps you could ask for a separate question. Please state your intent too, as you might not even need such expressions. – orcun Feb 24 '13 at 19:53
  • My intent is to derive a classname with a variable value when a condition is met. without doing it in the controller, is this possible? – Casey Feb 24 '13 at 23:49
  • @Casey, I was asking, what you really want to happen in the end. Deriving class name is probably not your only option. I would gladly try to help if your intent was clear, but I cant think of a reason why you need such capability. That is why I suggested asking a separate question. – orcun Feb 25 '13 at 15:15
  • I realize there may be workarounds for my particular use case (which I am already employing), but I'm interested in a solution for the abstract problem -- or knowing definitively that there isn't one. – Casey Feb 25 '13 at 21:14
  • @Casey, it is not a workaround if a solution does not necessary have the same problem. Without knowing about your problem, let me tell you what I mean by that. Perhaps you could use two ng-class directives, one for item-focus and another for index. In CSS, you could then check for existence of both classes using something like .item-focus.4 If this solves your issue, I would not consider this as a workaround. It is using right tools for right purposes. If this does not solve your issue, that again means you should ask a separate question. – orcun Feb 26 '13 at 16:28
  • The "new" syntax is buggy for me (as of v1.1.5). My code `ng-class="{'favoriteon': favorite > 0 , 'favorite': favorite === 0, '': favorite < 0}` would correctly evaluate my initial (server) value and then make one correct toggle. The third toggle would break. Seems like a three state switch does not work correctly with this syntax. I had to revert to the "old" array based syntax to achieve the desired result. My code works with: `ng-class="{'1':'favoriteon', '0':'favorite', '-1':'@Model.FavoriteClass'}[favorite]` – kmehta Aug 27 '13 at 00:39
  • what should I do if I want customize only one of several classes this way? ex.: `active` class in `class="well view active"` – vp_arth May 06 '14 at 09:09
  • very useful article http://tech-blog.maddyzone.com/javascript/conditionally-apply-classes-in-angularjs – Rituraj ratan Sep 27 '14 at 06:58
  • {'classname': condition} is work for me (note the ' '). – Alexandr May 20 '16 at 17:14
  • 1
    on a class name with a hyphen (-) in it you need to use quotes. eg `ng-class="{'my-class':somePotentiallyNullVariable}"` – Jacksonkr Feb 08 '17 at 20:39
437

ng-class supports an expression that must evaluate to either

  1. A string of space-delimited class names, or
  2. An array of class names, or
  3. A map/object of class names to boolean values.

So, using form 3) we can simply write

ng-class="{'selected': $index==selectedIndex}"

See also How do I conditionally apply CSS styles in AngularJS? for a broader answer.


Update: Angular 1.1.5 has added support for a ternary operator, so if that construct is more familiar to you:

ng-class="($index==selectedIndex) ? 'selected' : ''"
Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 2
    +1 for ternary operators (and I need one right now) but 1.1.* is an 'unstable release' where the API is subject to change without notice - as of time of typing. 1.0.* is stable, so I'd be more comfortable going with that for a project to be rolled out next week for 6 months. – Dave Everitt Oct 28 '13 at 16:24
  • 1
    `ng-class="{'selected': $index==selectedIndex}"` works for me – Knut Holm Feb 06 '15 at 15:19
158

My favorite method is using the ternary expression.

ng-class="condition ? 'trueClass' : 'falseClass'"

Note: Incase you're using a older version of Angular you should use this instead,

ng-class="condition && 'trueClass' || 'falseClass'"
skmvasu
  • 3,098
  • 3
  • 24
  • 29
  • 2
    This helped me writing this expression: `ng-class="property.name=='timestamp' ? 'property-timestamp' : 'property-'+{{$index}}"`. Could not figure out any other way. – dduft Jan 29 '15 at 10:54
  • I am really not finding why my scoped boolean modalFlag is not updating - ng-class="{'closed': modalFlag , 'open':!modalFlag}" I am trying to add either closed or open depending on the scoped variable/boolean - if anyone can help I would be very grateful -thank you. – landed May 27 '15 at 17:56
  • This was introduced as 1.5 version. https://github.com/angular/angular.js/commit/6798fec4390a72b7943a49505f8a245b6016c84b – Mubashir Koul Feb 15 '17 at 20:11
53

I'll add to this, because some of these answers seem out of date. Here's how I do it:

<class="ng-class:isSelected">

Where 'isSelected' is a javascript variable defined within the scoped angular controller.


To more specifically address your question, here's how you might generate a list with that:

HTML

<div ng-controller="ListCtrl">  
    <li class="ng-class:item.isSelected" ng-repeat="item in list">   
       {{item.name}}
    </li>  
</div>


JS

function ListCtrl($scope) {    
    $scope.list = [  
        {"name": "Item 1", "isSelected": "active"},  
        {"name": "Item 2", "isSelected": ""}
    ]
}


See: http://jsfiddle.net/tTfWM/

See: http://docs.angularjs.org/api/ng.directive:ngClass

stefano
  • 3,753
  • 1
  • 22
  • 15
48

Here is a much simpler solution:

function MyControl($scope){
    $scope.values = ["a","b","c","d","e","f"];
    $scope.selectedIndex = -1;
    
    $scope.toggleSelect = function(ind){
        if( ind === $scope.selectedIndex ){
            $scope.selectedIndex = -1;
        } else{
            $scope.selectedIndex = ind;
        }
    }
    
    $scope.getClass = function(ind){
        if( ind === $scope.selectedIndex ){
            return "selected";
        } else{
            return "";
        }
    }
       
    $scope.getButtonLabel = function(ind){
        if( ind === $scope.selectedIndex ){
            return "Deselect";
        } else{
            return "Select";
        }
    }
}
.selected {
    color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<div ng-app ng-controller="MyControl">
    <ul>
        <li ng-class="getClass($index)" ng-repeat="value in values" >{{value}} <button ng-click="toggleSelect($index)">{{getButtonLabel($index)}}</button></li>
    </ul>
    <p>Selected: {{selectedIndex}}</p>
</div>
  • 74
    I'd highly recommend to keep your controller clear of CSS stuff. That's a path you don't want to head down. – leviathan Jul 09 '12 at 06:59
  • 1
    Class names belong in the template – Casey Jan 29 '13 at 09:07
  • 5
    At some point, jsfiddle may miss to pay their bills, or choose to move to another domain, or the responsible people get killed by a bus (see also Bus Factor). So may I ask you to explain what that fiddle does, _within_ your answer? This is also canonical on stack overflow. – Sebastian Mach Oct 10 '14 at 09:06
27

I faced a similar problem recently and decided to just create a conditional filter:

  angular.module('myFilters', []).
    /**
     * "if" filter
     * Simple filter useful for conditionally applying CSS classes and decouple
     * view from controller 
     */
    filter('if', function() {
      return function(input, value) {
        if (typeof(input) === 'string') {
          input = [input, ''];
        }
        return value? input[0] : input[1];
      };
    });

It takes a single argument, which is either a 2-element array or a string, which gets turned into an array that is appended an empty string as the second element:

<li ng-repeat="item in products | filter:search | orderBy:orderProp |
  page:pageNum:pageLength" ng-class="'opened'|if:isOpen(item)">
  ...
</li>
Lèse majesté
  • 7,923
  • 2
  • 33
  • 44
  • 1
    me to I just created for exemple a yesNo() filter returning classes 'yes' or 'no' according to a boolean value 1 o 0 : `filter('yesNo', function() { return function(input) { // info('yesNo('+ input +')'); switch(input){ case '1': return ' yes '; break; default: return ' no '; break; } } });` – svassr Aug 01 '12 at 20:11
  • 1
    ng-class can handle a map/object of class names to boolean values, so you could simply write the following: ng-class="{yes: some_boolean_expression, no: some_other_boolean_expression}" E.g., ng-class="{yes: input, no: !input}" – Mark Rajcok Aug 28 '12 at 01:21
21

If you want to go beyond binary evaluation and keep your CSS out of your controller you can implement a simple filter that evaluates the input against a map object:

angular.module('myApp.filters, [])
  .filter('switch', function () { 
      return function (input, map) {
          return map[input] || '';
      }; 
  });

This allows you to write your markup like this:

<div ng-class="muppets.star|switch:{'Kermit':'green', 'Miss Piggy': 'pink', 'Animal': 'loud'}">
    ...
</div>
Joe Steele
  • 691
  • 5
  • 12
  • Hi @Joe, any ideas how to handle null values? If i pass in null in the input, it wont map its class... – dalcam Apr 23 '14 at 12:02
  • 1
    @user1191559 - you could a 'default' item to the map, then return that value if 'input' is null. – Joe Steele Apr 25 '14 at 10:18
17

The was I recently did that was doing this:

<input type="password"  placeholder="Enter your password"
ng-class="{true: 'form-control isActive', false: 'isNotActive'}[isShowing]">

The isShowing value is a value that is located on my controller that gets toggled with the click of a button and the parts between the single parenthesis are classes I created in my css file.

EDIT: I would also like to add that codeschool.com has a free course that is sponsored by google on AngularJS that goes over all of this stuff and then some. There is no need to pay for anything, just signup for an account and get going! Best of luck to you all!

Pytth
  • 4,008
  • 24
  • 29
15

Ternary operator has just been added to angular parser in 1.1.5.

So the simplest way to do this is now :

ng:class="($index==selectedIndex)? 'selected' : ''"
lionroots
  • 284
  • 3
  • 5
11

We can make a function to manage return class with condition

enter image description here

<script>
    angular.module('myapp', [])
            .controller('ExampleController', ['$scope', function ($scope) {
                $scope.MyColors = ['It is Red', 'It is Yellow', 'It is Blue', 'It is Green', 'It is Gray'];
                $scope.getClass = function (strValue) {
                    switch(strValue) {
                        case "It is Red":return "Red";break;
                        case "It is Yellow":return "Yellow";break;
                        case "It is Blue":return "Blue";break;
                        case "It is Green":return "Green";break;
                        case "It is Gray":return "Gray";break;
                    }
                }
        }]);
</script>

And then

<body ng-app="myapp" ng-controller="ExampleController">

<h2>AngularJS ng-class if example</h2>
<ul >
    <li ng-repeat="icolor in MyColors" >
        <p ng-class="[getClass(icolor), 'b']">{{icolor}}</p>
    </li>
</ul>
<hr/>
<p>Other way using : ng-class="{'class1' : expression1, 'class2' : expression2,'class3':expression2,...}"</p>
<ul>
    <li ng-repeat="icolor in MyColors">
        <p ng-class="{'Red':icolor=='It is Red','Yellow':icolor=='It is Yellow','Blue':icolor=='It is Blue','Green':icolor=='It is Green','Gray':icolor=='It is Gray'}" class="b">{{icolor}}</p>
    </li>
</ul>

You can refer to full code page at ng-class if example

erier
  • 1,744
  • 1
  • 11
  • 14
Lewis Hai
  • 1,114
  • 10
  • 22
9

I am new to Angular but have found this to solve my issue:

<i class="icon-download" ng-click="showDetails = ! showDetails" ng-class="{'icon-upload': showDetails}"></i>

This will conditionally apply a class based on a var. It starts off with a icon-download as a default, the using ng-class, I check the status of showDetails if true/false and apply class icon-upload. Its working great.

Hope it helps.

Ravi Ram
  • 24,078
  • 21
  • 82
  • 113
9

This works like a charm ;)

<ul class="nav nav-pills" ng-init="selectedType = 'return'">
    <li role="presentation" ng-class="{'active':selectedType === 'return'}"
        ng-click="selectedType = 'return'"><a href="#return">return

    </a></li>
    <li role="presentation" ng-class="{'active':selectedType === 'oneway'}"
        ng-click="selectedType = 'oneway'"><a href="#oneway">oneway
    </a></li>
</ul>
Daniel B
  • 3,109
  • 2
  • 33
  • 42
Aliti
  • 2,025
  • 2
  • 27
  • 39
5

This will probably get downvoted to oblivion, but here is how I used 1.1.5's ternary operators to switch classes depending on whether a row in a table is the first, middle or last -- except if there is only one row in the table:

<span class="attribute-row" ng-class="(restaurant.Attributes.length === 1) || ($first ? 'attribute-first-row': false || $middle ? 'attribute-middle-row': false || $last ? 'attribute-last-row': false)">
</span>
sundar
  • 71
  • 1
  • 3
5

This is in my work multiple conditionally judge:

<li ng-repeat='eOption in exam.examOptions' ng-class="exam.examTitle.ANSWER_COM==exam.examTitle.RIGHT_ANSWER?(eOption.eoSequence==exam.examTitle.ANSWER_COM?'right':''):eOption.eoSequence==exam.examTitle.ANSWER_COM?'wrong':eOption.eoSequence==exam.examTitle.RIGHT_ANSWER?'right':''">
  <strong>{{eOption.eoSequence}}</strong> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;
  <span ng-bind-html="eOption.eoName | to_trusted">2020 元</span>
</li>
Ben Kalsky
  • 148
  • 2
  • 16
H.jame
  • 79
  • 1
  • 6
4

Here is another option that works well when ng-class can't be used (for example when styling SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)

Ashley Davis
  • 9,896
  • 7
  • 69
  • 87
4

partial

  <div class="col-md-4 text-right">
      <a ng-class="campaign_range === 'thismonth' ? 'btn btn-blue' :  'btn btn-link'" href="#" ng-click='change_range("thismonth")'>This Month</a>
      <a ng-class="campaign_range === 'all' ? 'btn btn-blue' :  'btn btn-link'" href="#" ng-click='change_range("all")'>All Time</a>
  </div>

controller

  $scope.campaign_range = "all";
  $scope.change_range = function(range) { 
        if (range === "all")
        {
            $scope.campaign_range = "all"
        }
        else
        {  
            $scope.campaign_range = "thismonth"
        }
  };
George Kagan
  • 5,913
  • 8
  • 46
  • 50
Caner
  • 1,448
  • 23
  • 38
4

well i would suggest you to check condition in your controller with a function returning true or false .

<div class="week-wrap" ng-class="{today: getTodayForHighLight(todayDate, day.date)}">{{day.date}}</div>

and in your controller check the condition

$scope.getTodayForHighLight = function(today, date){
return (today == date);
}
Sheelpriy
  • 1,675
  • 17
  • 28
3

Check this.

The infamous AngularJS if|else statement!!!
When I started using Angularjs, I was a bit surprised that I couldn’t find an if/else statement.

So I was working on a project and I noticed that when using the if/else statement, the condition shows while loading. You can use ng-cloak to fix this.

<div class="ng-cloak">
 <p ng-show="statement">Show this line</span>
 <p ng-hide="statement">Show this line instead</span>
</div>

.ng-cloak { display: none }

Thanks amadou

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
Victor Cruz
  • 133
  • 1
  • 3
3

If you are using angular pre v1.1.5 (i.e. no ternary operator) and you still want an equivalent way to set a value in both conditions you can do something like this:

ng-class="{'class1':item.isReadOnly == false, 'class2':item.isReadOnly == true}"
Scotty.NET
  • 12,533
  • 4
  • 42
  • 51
3

If you having a common class that is applied to many elements you can create a custom directive that will add that class like ng-show/ng-hide.

This directive will add the class 'active' to the button if it's clicked

module.directive('ngActive',  ['$animate', function($animate) {
  return function(scope, element, attr) {
    scope.$watch(attr.ngActive, function ngActiveWatchAction(value){
      $animate[value ? 'addClass' : 'removeClass'](element, 'active');
    });
  };
}]);

More info

lars1595
  • 886
  • 3
  • 12
  • 27
3

Just adding something that worked for me today, after much searching...

<div class="form-group" ng-class="{true: 'has-error'}[ctrl.submitted && myForm.myField.$error.required]">

Hope this assists in your successful development.

=)

Undocumented Expression Syntax : Great Website Link... =)

Robert Green MBA
  • 1,834
  • 1
  • 22
  • 45
0

You can use this npm package. It handles everything and has options for static and conditional classes based on a variable or a function.

// Support for string arguments
getClassNames('class1', 'class2');

// support for Object
getClassNames({class1: true, class2 : false});

// support for all type of data
getClassNames('class1', 'class2', ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames({class1: true, class2 : false})} />
Tushar Sharma
  • 192
  • 1
  • 15
0

I understand this question id for angular, but if anyone is using React or a React-Based Framework (Amplify, NextJS, Serverless, etc.) The solution is significantly easier. The most performant way is with a ternary operator like so:

<div className={condition ? "classnameiftrue" : "classnameiffalse"}>

You can use this strategy to animate the tree if using useState() as each time the state changes it will reload that conditional with the new value.

cmcnphp
  • 400
  • 1
  • 4
  • 14