Angular && condition doesn't work - angularjs

I use following code snip.
<div data-ng-class="{ sel_style : $index!=0 && {{selClaz.row[$index].colorId }} == {{selClaz.row[$index-1].colorId }} }" >
Here what is done is, a CSS style is assigned to a div based on a condition. Also, 'selClaz.row' is iterated and if the current object's colorId value is equal to previous object, then the final boolean expression should be true. But this should not be executed for first iteration which is $index==0 . Therefore, a condition to avoid execution for first index, $index !=0 is added. But exception is thrown mentioning above line has syntax error. console further shows && for above && . So how can I fix this ? I use angular 1.3

Couple things wrong with your ng-class
-You need to wrap your class in quotes, due to the _
-You dont need {{}} in ng-class directive
data-ng-class="{ 'sel_style' : $index!=0 && selClaz.row[$index].colorId == selClaz.row[$index-1].colorId }"

Related

Is ng-class directive condition always displayed in DOM?

I'm completely new in AngularJS. I wrote this code:
<div ng-class="myString != 'true' ? 'class-one' : 'class-two'">
// my code that I want to display
</div>
And I noticed that this condition is displayed in the developer tools. Is this a default behavior by AngularJS or I'm just doing something wrong?
Maybe there is a possibility to just apply those classes dynamically without showing its condition in the dom?
Is this a default behavior by AngularJS or I'm just doing something wrong?
No it is not the default behavior
The correct syntax of ng-class is this:
<div ng-class="{ 'class-one': myString == 'true' , 'class-two': myString != 'true' }">
Another way is to use class and the ternary expression as you wrote it:
<div class="{{ myString != 'true' ? 'class-one' : 'class-two' }}">

Remove a class added conditionally using ng-class

I add a class another-class based on condition as follows using ng-class.Is it possible to remove that another-class using ng-class when the condition is not met? Right now the class another-class just remains in the element even when the condition is not met!
<div ng-hide="ok.isTrue" ng-class = "'{{ok.Id}}' === '{{notok.Id}}' ? 'another-class': '' ;" class="some-class">
You can use different ng-class syntax for this, particularly the map syntax:
ng-class="{'another-class': ok.Id === notok.Id}"

Angular JS 1.3+ One time binding for ng-bind with a ternary condition

Would this be correct if I need to use one time binding for a ternary condition inside data-ng-bind directive?
<span data-ng-bind="::model.boolean ? 'json.item.value1' : 'json.item.value2'"></span>
or
<span data-ng-bind="::(model.boolean ? 'json.item.value1' : 'json.item.value2')"></span>
Yes. The whole expression, whatever it is, will be parsed and read once.
What will happen internally would be equivalent to:
// If not bound
value = $parse("model.boolean ? 'json.item.value1' : 'json.item.value2'")(scope)
Note: If model.boolean is true, you will actually see the string "json.item.value1" and not the real value it contains. If you want to evaluate that, you need to remove the single quotes ' so it becomes:
<span data-ng-bind="::model.boolean ? json.item.value1 : json.item.value2"></span>

Is it possible to have multiple separate ternary expressions in ng-class for an element?

I am trying to combine the following two ng-class ternary expressions into one ng-class (so I can control both the color, via btn-success/danger classes, and the width, via width-small/medium/wide class, of my button divs
<div class="btn" ng-class="(rate > 0) ? 'btn-success' : 'btn-danger'">{{rate}}</div>
<div class="btn" ng-class="(priority == 'low') ? 'width-small' : (priority == 'medium') ? 'width-medium' : 'width-wide'">{{rate}}</div>
I realize I could just do something along the lines of below; however, I would like to make use of the ternary expressions available in 1.1.5
<div class="btn" ng-class="{'btn-success': rate > 0, 'btn-danger': rate <= 0, 'width-small': priority == 'low', 'width-medium': priority == 'medium', 'width-wide': prioity == 'high'}">{{rate}}</div>
Space separating the expressions did not work for me, nor did comma separating them within ng-class
Thanks advance for your assistance in determining if/how to have multiple ternary expressions in a single ng-class
For anyone looking for the answer: Yes this is indeed possible, also as mentioned the readability is questionable.
<div ng-class="(conversation.read ? 'read' : 'unread') + ' ' + (conversation.incoming ? 'in' : 'out')"></div>
From the ngClass documentation:
The directive operates in three different ways, depending on which of >three types the expression evaluates to:
If the expression evaluates to a string, the string should be one or >more space-delimited class names.
If the expression evaluates to an array, each element of the array >should >be a string that is one or more space-delimited class names.
If the expression evaluates to an object, then for each key-value pair of >the object with a truthy value the corresponding key is used as a class >name.
Option 1 applies here.
From my understanding using this method will result in 2 watches while using object notation will result in 4, but I might be wrong on this one.
I think you'd rather use a filter. You could write a rateToClass filter that would hold the logic and transform your rate in the class name that you want.
You could also put a rateToClass(rate) function in your scope, but it's ugly.
If you insist on having your logic in the view,
ng-class support multiple classes by using an object (see official doc first example, line 7):
<p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
You can have more complexe expression like ng-class='{btn-success: rate > 0}'.
It is possible to add multiple ternary expressions on a single ng-class directive by putting each of the expressions into an array, as items of this array.
Example :
<div ng-class="[
expression1 ? 'class1' : 'class2',
expression2 ? 'class3' : 'class4'
]">

What is the best way to conditionally apply attributes in AngularJS?

I need to be able to add for example "contenteditable" to elements, based on a boolean variable on scope.
Example use:
<h1 attrs="{'contenteditable=\"true\"': editMode}">{{content.title}}</h1>
Would result in contenteditable=true being added to the element if $scope.editMode was set to true.
Is there some easy way to implement this ng-class like attribute behavior? I'm considering writing a directive and sharing if not.
Edit:
I can see that there seems to be some similarities between my proposed attrs directive and ng-bind-attrs, but it was removed in 1.0.0.rc3, why so?
I am using the following to conditionally set the class attr when ng-class can't be used (for example when styling SVG):
ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"
The same approach should work for other attribute types.
(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)
You can prefix attributes with ng-attr to eval an Angular expression. When the result of the expressions undefined this removes the value from the attribute.
<a ng-attr-href="{{value || undefined}}">Hello World</a>
Will produce (when value is false)
<a ng-attr-href="{{value || undefined}}" href>Hello World</a>
So don't use false because that will produce the word "false" as the value.
<a ng-attr-href="{{value || false}}" href="false">Hello World</a>
When using this trick in a directive. The attributes for the directive will be false if they are missing a value.
For example, the above would be false.
function post($scope, $el, $attr) {
var url = $attr['href'] || false;
alert(url === false);
}
I got this working by hard setting the attribute. And controlling the attribute applicability using the boolean value for the attribute.
Here is the code snippet:
<div contenteditable="{{ condition ? 'true' : 'false'}}"></div>
In the latest version of Angular (1.1.5), they have included a conditional directive called ngIf. It is different from ngShow and ngHide in that the elements aren't hidden, but not included in the DOM at all. They are very useful for components which are costly to create but aren't used:
<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>
To get an attribute to show a specific value based on a boolean check, or be omitted entirely if the boolean check failed, I used the following:
ng-attr-example="{{params.type == 'test' ? 'itWasTest' : undefined }}"
Example usage:
<div ng-attr-class="{{params.type == 'test' ? 'itWasTest' : undefined }}">
Would output <div class="itWasTest"> or <div> based on the value of params.type
<h1 ng-attr-contenteditable="{{isTrue || undefined }}">{{content.title}}</h1>
will produce when isTrue=true :
<h1 contenteditable="true">{{content.title}}</h1>
and when isTrue=false :
<h1>{{content.title}}</h1>
Regarding the accepted solution, the one posted by Ashley Davis, the method described still prints the attribute in the DOM, regardless of the fact that the value it has been assigned is undefined.
For example, on an input field setup with both an ng-model and a value attribute:
<input type="text" name="myInput" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
Regardless of what's behind myValue, the value attribute still gets printed in the DOM, thus, interpreted. Ng-model then, becomes overridden.
A bit unpleasant, but using ng-if does the trick:
<input type="text" name="myInput" data-ng-if="value" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
<input type="text" name="myInput" data-ng-if="!value" data-ng-model="myModel" />
I would recommend using a more detailed check inside the ng-if directives :)
Also you can use an expression like this:
<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>
I actually wrote a patch to do this a few months ago (after someone asked about it in #angularjs on freenode).
It probably won't be merged, but it's very similar to ngClass: https://github.com/angular/angular.js/pull/4269
Whether it gets merged or not, the existing ng-attr-* stuff is probably suitable for your needs (as others have mentioned), although it might be a bit clunkier than the more ngClass-style functionality that you're suggesting.
For input field validation you can do:
<input ng-model="discount" type="number" ng-attr-max="{{discountType == '%' ? 100 : undefined}}">
This will apply the attribute max to 100 only if discountType is defined as %
Edit: This answer is related to Angular2+! Sorry, I missed the tag!
Original answer:
As for the very simple case when you only want to apply (or set) an attribute if a certain Input value was set, it's as easy as
<my-element [conditionalAttr]="optionalValue || false">
It's the same as:
<my-element [conditionalAttr]="optionalValue ? optionalValue : false">
(So optionalValue is applied if given otherwise the expression is false and attribute is not applied.)
Example: I had the case, where I let apply a color but also arbitrary styles, where the color attribute didn't work as it was already set (even if the #Input() color wasn't given):
#Component({
selector: "rb-icon",
styleUrls: ["icon.component.scss"],
template: "<span class="ic-{{icon}}" [style.color]="color==color" [ngStyle]="styleObj" ></span>",
})
export class IconComponent {
#Input() icon: string;
#Input() color: string;
#Input() styles: string;
private styleObj: object;
...
}
So, "style.color" was only set, when the color attribute was there, otherwise the color attribute in the "styles" string could be used.
Of course, this could also be achieved with
[style.color]="color"
and
#Input color: (string | boolean) = false;
Was able to get this working:
ng-attr-aria-current="{{::item.isSelected==true ? 'page' : undefined}}"
The nice thing here is that if item.isSelected is false then the attribute simply isn't rendered.
Just in case you need solution for Angular 2 then its simple, use property binding like below, e.g. you want to make input read only conditionally, then add in square braces the attrbute followed by = sign and expression.
<input [readonly]="mode=='VIEW'">

Resources