AngularJS offers support for powerful expressions within templates. Unfortunately, you cannot write a control flow statement in an expression (conditionals, loops, or throw). According to the documentation, “the reason behind this is core to the angular philosophy that application logic should be in controllers, not in the view. If you need a conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.”
This is a bit of a shame, especially when trying to add a class to specific elements within an iterator (loop, using ng-repeat), either the first one, the last one, or any element in the middle. This is especially frustrating since AngularJS conveniently provides special properties for it ($index, $first, $middle, $last). Separation of concerns should be a philosophy, not a religion, and many control flow statements really belong to the view, not to the controller.
In order to work around this problem, we just created the following helper function:
$scope.isOn = function(elementPosition, className) {
return elementPosition ? className : null;
}
We added this function to our controller and invoked it from our templates like that:
class="{{isOn($first, 'active')}}"
This will add the active class to the first element within a list. Of course, the very same function can be used with $middle and $last as well. We implemented this helper function in order to activate the first tab of our record view now that we’re dynamically generating the record view’s structure based on a JSON definition (more on this later).
UPDATE: We just learned that ternary operators are supported in expressions. This was documented in this stackoverflow answer and we tested it within our code. It removes the need for the helper function we implemented, and makes the code a lot more readable:
ng:class="{true:'active', false:''}[$first]"