'use strict'; function classDirective(name, selector) { name = 'ngClass' + name; return function() { return { restrict: 'AC', link: function(scope, element, attr) { var oldVal = undefined; scope.$watch(attr[name], ngClassWatchAction, true); attr.$observe('class', function(value) { ngClassWatchAction(scope.$eval(attr[name])); }); if (name !== 'ngClass') { scope.$watch('$index', function($index, old$index) { var mod = $index & 1; if (mod !== old$index & 1) { if (mod === selector) { addClass(scope.$eval(attr[name])); } else { removeClass(scope.$eval(attr[name])); } } }); } function ngClassWatchAction(newVal) { if (selector === true || scope.$index % 2 === selector) { if (oldVal && !equals(newVal,oldVal)) { removeClass(oldVal); } addClass(newVal); } oldVal = copy(newVal); } function removeClass(classVal) { attr.$removeClass(flattenClasses(classVal)); } function addClass(classVal) { attr.$addClass(flattenClasses(classVal)); } function flattenClasses(classVal) { if(isArray(classVal)) { return classVal.join(' '); } else if (isObject(classVal)) { var classes = [], i = 0; forEach(classVal, function(v, k) { if (v) { classes.push(k); } }); return classes.join(' '); } return classVal; }; } }; }; } /** * @ngdoc directive * @name ng.directive:ngClass * @restrict AC * * @description * The `ngClass` allows you to set CSS classes on HTML an element, dynamically, by databinding * an expression that represents all classes to be added. * * The directive won't add duplicate classes if a particular class was already set. * * When the expression changes, the previously added classes are removed and only then the * new classes are added. * * @animations * add - happens just before the class is applied to the element * remove - happens just before the class is removed from the element * * @element ANY * @param {expression} ngClass {@link guide/expression Expression} to eval. The result * of the evaluation can be a string representing space delimited class * names, an array, or a map of class names to boolean values. In the case of a map, the * names of the properties whose values are truthy will be added as css classes to the * element. * * @example Example that demostrates basic bindings via ngClass directive.

Map Syntax Example

bold strike red

Using String Syntax


Using Array Syntax




.strike { text-decoration: line-through; } .bold { font-weight: bold; } .red { color: red; } it('should let you toggle the class', function() { expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/); expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/); input('bold').check(); expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/); input('red').check(); expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/); }); it('should let you toggle string example', function() { expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe(''); input('style').enter('red'); expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red'); }); it('array example should have 3 classes', function() { expect(element('.doc-example-live p:last').prop('className')).toBe(''); input('style1').enter('bold'); input('style2').enter('strike'); input('style3').enter('red'); expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red'); });
## Animations The example below demonstrates how to perform animations using ngClass.
Sample Text
.my-class-add, .my-class-remove { -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; } .my-class, .my-class-add.my-class-add-active { color: red; font-size:3em; } .my-class-remove.my-class-remove-active { font-size:1.0em; color:black; } it('should check ng-class', function() { expect(element('.doc-example-live span').prop('className')).not(). toMatch(/my-class/); using('.doc-example-live').element(':button:first').click(); expect(element('.doc-example-live span').prop('className')). toMatch(/my-class/); using('.doc-example-live').element(':button:last').click(); expect(element('.doc-example-live span').prop('className')).not(). toMatch(/my-class/); });
## ngClass and pre-existing CSS3 Transitions/Animations The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure. Therefore, if any CSS3 Transition/Animation styles (outside of ngAnimate) are set on the element, then, if a ngClass animation is triggered, the ngClass animation will be skipped so that ngAnimate can allow for the pre-existing transition or animation to take over. This restriction allows for ngClass to still work with standard CSS3 Transitions/Animations that are defined outside of ngAnimate. */ var ngClassDirective = classDirective('', true); /** * @ngdoc directive * @name ng.directive:ngClassOdd * @restrict AC * * @description * The `ngClassOdd` and `ngClassEven` directives work exactly as * {@link ng.directive:ngClass ngClass}, except they work in * conjunction with `ngRepeat` and take effect only on odd (even) rows. * * This directive can be applied only within the scope of an * {@link ng.directive:ngRepeat ngRepeat}. * * @element ANY * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result * of the evaluation can be a string representing space delimited class names or an array. * * @example
  1. {{name}}
.odd { color: red; } .even { color: blue; } it('should check ng-class-odd and ng-class-even', function() { expect(element('.doc-example-live li:first span').prop('className')). toMatch(/odd/); expect(element('.doc-example-live li:last span').prop('className')). toMatch(/even/); });
*/ var ngClassOddDirective = classDirective('Odd', 0); /** * @ngdoc directive * @name ng.directive:ngClassEven * @restrict AC * * @description * The `ngClassOdd` and `ngClassEven` directives work exactly as * {@link ng.directive:ngClass ngClass}, except they work in * conjunction with `ngRepeat` and take effect only on odd (even) rows. * * This directive can be applied only within the scope of an * {@link ng.directive:ngRepeat ngRepeat}. * * @element ANY * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The * result of the evaluation can be a string representing space delimited class names or an array. * * @example
  1. {{name}}      
.odd { color: red; } .even { color: blue; } it('should check ng-class-odd and ng-class-even', function() { expect(element('.doc-example-live li:first span').prop('className')). toMatch(/odd/); expect(element('.doc-example-live li:last span').prop('className')). toMatch(/even/); });
*/ var ngClassEvenDirective = classDirective('Even', 1);