Angular's ng-class: combine enumerated (array) classes and condition-based ones? - angularjs

I have an array with classes set in the controller (has to be this way, it's read from page's meta-template). I'd also like to have a conditional classes applied to the same element. Is it possible?
Edit, more info: my html element has classes that originate from two sources - one is a set of classes created by the controller (they are provided by a service outside of my code, I can't have them hardcoded in the view). The other source is an output of a condition (for example: if "$scope.activeElement === name_of_this_element, add 'active' class).
In ng-class directive, I can't use an object notation for unspecified list of classes (the first source) and I have to use an object notation for conditional classes.
Edit: found a solution (see below).

Another option is to write an ng-class in this way
<div ng-class="[item.class, item.errorClass, item.locked ? 'locked-item' : '']"></div>

I found a solution - I placed the "fixed" classes in a regular class attribute (converted that string to an array first) and conditional ones in ng-class object, like this:
<td ng-repeat="cell in row.cells" class="{{cell.cssClass}}" ng-class="{active: condition}">

The fact that you stored a array of classes' name is not relevant here.
HTML
<div ng-class="arrOfClasses[condition]"></div>
Angular
app.controller('myCtrl', function($scope) {
$scope.arrOfClasses = ['class1', 'class2', 'class3'];
$scope.condition = 1; // what ever number here
});

A good way, and also to avoid using {{}} inside class would be with just an expression:
<td ng-repeat="cell in row.cells" ng-class="(condition ? 'active ' : '') + cell.cssClass">

Related

When to use ng-attr?

It seems like using direct attributes and the ng-attr-* directive do the same thing. For example, the following render equivalently:
<div ng-attr-id="{{ 'object-' + value }}">ID</div>
<div id="{{ 'object-' + value }}">ID</div>
When should I use ng-attr-* and when should I use the direct HTML attribute?
ng-attr is used for add or not the attribute in context. If the expression {{undefined || null}}, the attribute is not added otherwise if has a value then attribute is added with the value {{ value }}.
The most common cases is in interpolation.
Related:
Conditionally adding data-attribute in Angular directive template
You use them for custom html data attributes - like if you wanted an attribute of let's say myData you would do
<div ng-attr-myData="{{ 'object-' + value }}">ID</div>
There are only a few situations where ng-attr-[attribute]="{{angular stuff}}" is different from just [attribute]="{{angular stuff}}". Certain elements within certain browsers can be broken if ng-attr is not used. Angular's documentation lists a few examples:
size in <select> elements (see issue 1619)
placeholder in <textarea> in Internet Explorer 10/11 (see issue 5025)
type in <button> in Internet Explorer 11 (see issue 14117)
value in <progress> in Internet Explorer = 11 (see issue 7218)
Source: https://docs.angularjs.org/guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes
ng-attr can be used to dynamically assign value to an attribute of any html element.
One case, where I used it was to associate a label to a form control with dynamic id.
<label ng-attr-for="{{parameter.name}}">{{ parameter.name }}</label>
<input ng-attr-id="{{parameter.name}}" type="text">
Also, it can be used to assign dynamic value to a custom attribute.
Reference: here

What is the active:true construct in Angular js?

I am following the phonecat Angular tutorial here and I was wondering what this code was doing:
<div class="phone-images">
<img ng-src="{{img}}"
class="phone"
ng-repeat="img in phone.images"
ng-class="{active:mainImageUrl==img}">
</div>
Is {active:true} an angular construct? If so, what does it do and where is the documentation? Why the single {}?
Will {{img}} work in ng-src even though it's above the ng-repeat line?
ng-class is a directive, that expects an Angular expression. The type of the expression can be a string (the name of the class), an array of strings (the names of the classes), or an object where keys are the names of the classes, and values are booleans telling if the class must be added or not.
In that case, the expression is a literal JavaScript object, just as you would write it in JavaScript code:
var object = {active: mainImageUrl == img};
And the CSS class 'active' will thus be added if mainImageUrl == img is true.

Angularjs ng-class not updating when using object annotation style

I just noticed that something doesn't work in Angular (or it doesn't as I expected it to work) when using object in ng-class.
What do I expect?
When changing the name of a property in the object, the class should update accordingly.
What did I try?
I found that when I use object style annotation like
ng-class="{obj.prop: testExpression}" and the obj.prop changes (the expression keeping returning TRUE) the value inside ng-class changes but that in the class attribute doesn't.
the difference is between this [NOT WORKING]:
<tr ng-repeat="user in users" ng-class="{ {{user.genre}}: true}">
and this [WORKING]:
<tr ng-repeat="user in users" ng-class="user.genre">
See a plunkr here:
http://plnkr.co/edit/149ba2WQ5RK5XqLmWQWK?p=preview
The thing is I need to use object annotation in order to disable the class.
Is there something I am doing wrong or I just misunderstood Angular?
Or a third solution?
In short, { {{user.genre}}: true} is not a correct angularjs expression
For your solution, try ng-class="getClass(user.genre)"
and do whatever you want in getClass function
example
You are trying to evaluate an object here, hence for each key-value pair of object with a real (truthy) value the corresponding key is used as a class name. If you have single parameter you have to use like:
<tr ng-repeat="user in users" ng-class="user.genre: true">
In case of multiple parameter you have to use like:
<p ng-class="{strike: deleted, bold: important, red: error}">

Custom Angularjs directive vs. ng-class

Several times when creating or customizing a directive (either my own directive or for example https://github.com/dpiccone/ng-pageslide) I get a point where all the display logic is controlled by a single css class. At that point the directive boils down to adding and removing a single class. So instead of using a new directive I can simply use the ng-class directive (see an example here: https://gist.github.com/Hypercubed/8f40556eb0f6eddbcca3). Is there an advantage to the custom directive approach vs the ng-class/CSS styles approach? I guess the custom directive doesn't depend on $animate? Am I just doing it wrong?
Sorry for another directive vs. XXX question.
I think you're failing to see the forest for the all tress. You're focusing on a very minute detail and missing the larger picture. Directives are more than simply applying styles. I think an example is best. For example, take the rating directive. If you wanted to render a star rating model it might look like this:
<div ng-rating="album.rating" max="5"></div>
That may add the following to the DOM:
<ul class="inline">
<li ng-repeat="i in max">
<i ng-class="{ 'icon-start-empty': i > rating, 'icon-star': i <= rating }"></i>
</li>
</ul>
Under the covers ng-class it utilized, but that is only a part of the logic encapsulated in the rating directive. It allows the user to configure how many stars the rating is out of, and renders the same number of li elements. Then because you wrote a directive it allows you to reuse this logic where ever it's required. Using ng-class only works in that 1 location. If you want to do the same thing you're copying code which is a sign maybe you want to wrap that logic up in a directive.

dynamically change a html element's class by angualrjs

I'm trying to change some html elements' class attribute by AngularJs' $scope value. But it seems I can't.
<div class="{{object.someAtrribute}} > Content </div>
So, how can i do this actually?
Thanks.
You want to use the ng-class directive. It takes an object with a set of class names and boolean expressions:
<div ng-class="{'class-name': boolean}"></div>
So, in your example, you can do something like this:
<div ng-class="{'larger-than-content': item.foo > content}"></div>
Since this is an object, you can add several classes:
<div ng-class="{'one': foo == 1, 'two': foo == 2, 'three': foo == 3}"></div>
Note: The quotes on the class names are not necessary, although I often have dashes in my class-names. In that case, the quotes are necessary (you are describing a JS object), so I tend to use them always for consistency.

Resources