41

The AngularJS Noob Handbook has some code which reduces class manipulation to a simple expression and binding :

<a ng-click="flags.open=!flags.open">...<div ng-class="{active:flags.open}">

However, what is the expression syntax in ng-class? I understand that a vertical bar (|) would pass through a filter and that a filter can be passed parameters after a colon but the above code is doing something different. If the scope variable on the right evaluates to true then the expression on the left is included otherwise it's dropped.

Is this specific to the ng-class directive? Is there some documentation on http://docs.angularjs.org that explains this?

Phil
  • 2,232
  • 1
  • 26
  • 35

5 Answers5

100

This is mentioned briefly (too briefly, in my opinion) in the ngClass documentation. If you pass an object to ngClass, then it will apply each key of the object as a class to the element if that key's value is true. For example:

$scope.first = true
$scope.second = false
$scope.third = true

with

<div ng-class="{a: first, b: second, c: third}"></div>

would result in

<div class="a c"></div>
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 15
    (facepalm) Ah... I see it now in the documentation - 'a map of class names to boolean values.' That really isn't obvious but I should have scanned down to the comments too. Thanks Brandon and @Mark - I've seen you guys a lot in StackOverflow having subscribed to the AngularJS tag and you're both provided top-notch help. – Phil Feb 06 '13 at 18:23
  • 2
    Remember - If your class name contains a hyphen you must put quotes around it! Such as `
    `
    – John Henckel Dec 18 '15 at 20:05
46

you've probably also seen something like this:

<div ng-class="{true: 'complete'}[item.Id != 0]"></div>

Very rad syntax.

EDIT: What happens here, is that the "complete" class is added to the element if(item.Id != 0). Alternatively, we could write: <div ng-class="{false: 'cookieless'}[monsterEatsCookies('Elmo')]. As its decided by the monsterEatsCookies function, Elmo does not eat cookies so since this function returns false the html element gains a class called cookieless.

A simple example: <div ng-class="{false: 'DoubleNegative'}[1 == 0]. 1 !== 0 which is "false" -- the "DoubleNegative" class is added to the element.

<div ng-class="{  true:   'complete'  } [item.Id != 0]"></div>

`

            | |      | |          | | |            |
            | |result| |className | | |            |
            |                     | | |            |
            |       function      | | | condition  |

Addendum

Also, I just realized that you can use a variety of different keys to map to your condition. For example:

ng-class="{ true: 'highlight', undefined: 'mute' }[ item.hasValue ]"

The mute class will be applied if item has no "hasValue" property. Furthermore, you can apply a class for any given type or value:

{'Jonathan Chapman': 'embolden', '[object Object]': 'hide'}[ item.toString() ]

In the following collection, this would embolden a person's name while hiding items that are objects:

[
    'Jonathan Chapman',
    { aka: 'Johnny Applyseed' },
    'Brad Pitt',
    { details: 'Fights Zombies' }
]

With this, you could watch for specific values in any $scope property. I suppose this could come in very handy at times.

Cheers

Cody
  • 9,785
  • 4
  • 61
  • 46
  • 1
    It would be rad if you'd explain what that syntax does, and why, for me and other future readers. – XML Oct 13 '13 at 02:34
  • 1
    So, the bracketed expression following the object/map is a conditional? Is that syntax actually documented anywhere? Thanks! – XML Oct 14 '13 at 22:26
  • Actually, I haven't been able to find any docs on this, but I can assure that it works. A coworker lead me onto this, an it totally saved us tons of work using jQuery element selectors. Everything we needed was data-bound. – Cody Oct 15 '13 at 22:36
  • Is it possible to have more than one condition in the ng-class. I was looking to style an item with different css pending on the case. Is this possible? I tried with { true: 'complete' } [item.Id == 0] , { true: 'failed' } [item.Id == 1] and it wouldn't work – Calebj Mar 28 '14 at 02:17
  • this seems to not be documented anywhere! great finding! – Kat Lim Ruiz Oct 22 '14 at 17:28
  • 1
    Thanks for the explanation! This saved a whole lot of time. – Sarcastron Jan 26 '15 at 19:38
  • Glad to help! Sometimes the usual ng-class syntax doesn't quite cut it, as you're still left with some Unorganized-Complexity. – Cody Jan 26 '15 at 20:06
  • This is equivalent to ng-class="{'complete': item.id != 2}". If it gets more complicated, why wouldn't you just call on a function to return the truthfullness? ng-class="{'complete': item.isComplete()}" where isComplete() can be as complex as necessary – Skystrider Jul 22 '15 at 16:55
  • @Skychan, You wouldn't not use this if you prefer this methodology. If it gets more *complex*, you would without a doubt want to scale your code to accommodate this complexity, but that might make things *complicated*. https://en.wikipedia.org/wiki/Category:Complex_systems_theory – Cody Jul 23 '15 at 17:27
6
ng-click="flags.open=!flags.open"

switch the value of the flags.open to true or false.
And

ng-class="{active:flags.open}"  

decides whether the class active is present or not based on the value of flags.open.
Please see the Fiddle demonstrating the above example.

Muhammed Basil
  • 1,834
  • 1
  • 21
  • 39
2

like this example below :

div(ng-class=" condition ? ['class_one', 'class_two'] : ['class_three', 'class_four']")
Spy
  • 161
  • 1
  • 8
1

Here's how you can pass expression with filter:

 <div ng-class="{ 'customer-page': ('customer' | isRoute), 
  'orders-page': ('orders' | isRoute)  }">....</div>
a8m
  • 9,334
  • 4
  • 37
  • 40