Is there any way to make an expression for something like ng-class to be a conditional?
For example, I have tried the following:
<span ng-class="{test: 'obj.value1 == \'someothervalue\''}">test</span>
The issue with this code is that no matter what obj.value1 is, the class test is always applied to the element. Doing this:
<span ng-class="{test: obj.value2}">test</span>
As long as obj.value2 does not equal a truthy value, the class in not applied. Now I can work around the issue in the first example by doing this:
<span ng-class="{test: checkValue1()}">test</span>
Where the checkValue1 function looks like this:
$scope.checkValue1 = function() {
return $scope.obj.value === 'somevalue';
}
I am just wondering if this is how ng-class is supposed to work. I am also building a custom directive where I would like to do something similar to this. However, I can't find a way to watch an expression (and maybe that is impossible and the reason why it works like this).
Here is a plnkr to show what I mean.
Your first attempt was almost right, It should work without the quotes.
{test: obj.value1 == 'someothervalue'}
Here is a plnkr.
The ngClass directive will work with any expression that evaluates truthy or falsey, a bit similar to Javascript expressions but with some differences, you can read about here.
If your conditional is too complex, then you can use a function that returns truthy or falsey, as you did in your third attempt.
Just to complement: You can also use logical operators to form logical expressions like
ng-class="{'test': obj.value1 == 'someothervalue' || obj.value2 == 'somethingelse'}"
Using ng-class inside ng-repeat
<table>
<tbody>
<tr ng-repeat="task in todos"
ng-class="{'warning': task.status == 'Hold' , 'success': task.status == 'Completed',
'active': task.status == 'Started', 'danger': task.status == 'Pending' } ">
<td>{{$index + 1}}</td>
<td>{{task.name}}</td>
<td>{{task.date|date:'yyyy-MM-dd'}}</td>
<td>{{task.status}}</td>
</tr>
</tbody>
</table>
For each status in task.status a different class is used for the row.
Angular JS provide this functionality in ng-class Directive. In which you can put condition and also assign conditional class. You can achieve this in two different ways.
Type 1
<div ng-class="{0:'one', 1:'two',2:'three'}[status]"></div>
In this code class will be apply according to value of status value
if status value is 0 then apply class one
if status value is 1 then apply class two
if status value is 2 then apply class three
Type 2
<div ng-class="{1:'test_yes', 0:'test_no'}[status]"></div>
In which class will be apply by value of status
if status value is 1 or true then it will add class test_yes
if status value is 0 or false then it will add class test_no
I see great examples above but they all start with curly brackets (json map). Another option is to return a result based on computation. The result can also be a list of css class names (not just map). Example:
ng-class="(status=='active') ? 'enabled' : 'disabled'"
or
ng-class="(status=='active') ? ['enabled'] : ['disabled', 'alik']"
Explanation: If the status is active, the class enabled will be used. Otherwise, the class disabled will be used.
The list [] is used for using multiple classes (not just one).
There is a simple method which you could use with html class attribute and shorthand if/else. No need to make it so complex. Just use following method.
<div class="{{expression == true ? 'class_if_expression_true' : 'class_if_expression_false' }}">Your Content</div>
I am going to show you two methods by which you can dynamically apply ng-class
Step-1
By using ternary operator
<div ng-class="condition?'class1':'class2'"></div>
Output
If your condition is true then class1 will be applied to your element else class2 will be applied.
Disadvantage
When you will try to change the conditional value at run time the class somehow will not changed. So I will suggest you to go for step2 if you have requirement like dynamic class change.
Step-2
<div ng-class="{value1:'class1', value2:'class2'}[condition]"></div>
Output
if your condition matches with value1 then class1 will be applied to your element, if matches with value2 then class2 will be applied and so on. And dynamic class change will work fine with it.
Hope this will help you.
Angular syntax is to use the : operator to perform the equivalent of an if modifier
<div ng-class="{ 'clearfix' : (row % 2) == 0 }">
Add clearfix class to even rows. Nonetheless, expression could be anything we can have in normal if condition and it should evaluate to either true or false.
Using function with ng-class is a good option when someone has to run complex logic to decide the appropriate CSS class.
http://jsfiddle.net/ms403Ly8/2/
HTML:
<div ng-app>
<div ng-controller="testCtrl">
<div ng-class="getCSSClass()">Testing ng-class using function</div>
</div>
</div>
CSS:
.testclass { Background: lightBlue}
JavaScript:
function testCtrl($scope) {
$scope.getCSSClass = function() {
return "testclass ";
}
}
For Angular 2, use this
<div [ngClass]="{'active': dashboardComponent.selected_menu == 'mapview'}">Content</div>
use this
<div ng-class="{states}[condition]"></div>
for example if the condition is [2 == 2], states are {true: '...', false: '...'}
<div ng-class="{true: 'ClassA', false: 'ClassB'}[condition]"></div>
ng-class is a Directive of core AngularJs. In which you can use "String Syntax", "Array Syntax", "Evaluated Expression", " Ternary Operator" and many more options described below:
ngClass Using String Syntax
This is the simplest way to use ngClass. You can just add an Angular variable to
ng-class and that is the class that will be used for that element.
<!-- whatever is typed into this input will be used as the class for the div below -->
<input type="text" ng-model="textType">
<!-- the class will be whatever is typed into the input box above -->
<div ng-class="textType">Look! I'm Words!
Demo Example of ngClass Using String Syntax
ngClass Using Array Syntax
This is similar to the string syntax method except you are able to apply multiple classes.
<!-- both input boxes below will be classes for the div -->
<input type="text" ng-model="styleOne">
<input type="text" ng-model="styleTwo">
<!-- this div will take on both classes from above -->
<div ng-class="[styleOne, styleTwo]">Look! I'm Words!
ngClass Using Evaluated Expression
A more advanced method of using ngClass (and one that you will probably use the most) is to evaluate an expression. The way this works is that if a variable or expression evaluates to true, you can apply a certain class. If not, then the class won't be applied.
<!-- input box to toggle a variable to true or false -->
<input type="checkbox" ng-model="awesome"> Are You Awesome?
<input type="checkbox" ng-model="giant"> Are You a Giant?
<!-- add the class 'text-success' if the variable 'awesome' is true -->
<div ng-class="{ 'text-success': awesome, 'text-large': giant }">
Example of ngClass Using Evaluated Expression
ngClass Using Value
This is similar to the evaluated expression method except you just able to compares multiple values with the only variable.
<div ng-class="{value1:'class1', value2:'class2'}[condition]"></div>
ngClass Using the Ternary Operator
The ternary operator allows us to use shorthand to specify two different classes, one if an expression is true and one for false. Here is the basic syntax for the ternary operator:
ng-class="$variableToEvaluate ? 'class-if-true' : 'class-if-false'">
Evaluating First, Last or Specific Number
If you are using the ngRepeat directive and you want to apply classes to the first, last, or a specific number in the list, you can use special properties of ngRepeat. These include $first, $last, $even, $odd, and a few others. Here's an example of how to use these.
<!-- add a class to the first item -->
<ul>
<li ng-class="{ 'text-success': $first }" ng-repeat="item in items">{{ item.name }}</li>
</ul>
<!-- add a class to the last item -->
<ul>
<li ng-class="{ 'text-danger': $last }" ng-repeat="item in items">{{ item.name }}</li>
</ul>
<!-- add a class to the even items and a different class to the odd items -->
<ul>
<li ng-class="{ 'text-info': $even, 'text-danger': $odd }" ng-repeat="item in items">{{ item.name }}</li>
</ul>
Related
Actually I'm confused between when to use {{ }} when using angular directives and when to not to use {{ }}
For example:
<div data-ng-init="isHidden=false">
<div data-ng-show="isHidden">
...
</div>
</div>
and
<div data-ng-init="isHidden=false">
<div data-ng-show="{{isHidden}}">
...
</div>
</div>
I'm confused between these syntax ? What are the differences between those? And when to use what? Thanks in advance :)
There is no difference except the "look" u need to use the {{value}} syntax in case you want to write data anywhere in your html body
<div>{{value}}</div>
It's all explained here: Difference between double and single curly brace in angular JS?
For quick answer:
{{}} are Angular expressions and come quite handy when you wish to
write stuff to HTML
Don't use these at a place that is already an expression!
For instance, the directive ngClick treats anything written in between
the quotes as an expression
<div data-ng-init="isHidden=false">
<div data-ng-show="isHidden">
...
</div>
</div>
In This Situation data-ng-show = false , Takes From data-ng-init As Statically,if You Have Given true Then It Returns True .
But Here
<div data-ng-init="isHidden=false">
<div data-ng-show="{{isHidden}}">
...
</div>
{{}} Called As Expressions In Angular One Of The Most Important Concept
It Directly Evaluate If isHidden = true Or False Based On Any Condition Written In Your App.js File .
Example:
<div data-ng-init="isHidden=YourVariable">
<div data-ng-show="{{isHidden}}">
...
</div>
if(YourVariable == true){
Do Somthing
}
else{
Do Something
}
If you are asking when to use {{}} while assigning value to a attribute and when not.
It depends on the binding types of directive. '#' or '='
So here, you have to use:
data-ng-show="{{isHidden}}" if the binding type of directive scope data-ng-show is '#', that mean the data-ng-show will be expecting a string value. So in this case if you keep data-ng-show="isHidden" it will take data-ng-show's value as 'isHidden', but data-ng-show="{{isHidden}}" will take the value of the $scope.isHidden and assign to data-ng-show.
Now if the binding type of directive scope data-ng-show is '=', that means the data-ng-show will be expecting a value from a scope. So data-ng-show="isHidden" itself will take the value of he $scope.isHidden and assign to data-ng-show.
Note: all the default HTML attributes expect a string so you have to use {{}} for default HTML attributes.
There is no as such major difference unless one uses them in the DOM for the value.
When one uses the following:
<div data-ng-show="isHidden">
then, expression is evaluated and on the basis of it respective value, the ng-show either hides or displays the div. But the value of the isHidden cannot be seen, when one inspects the HTML using the browser developer tool.
When one uses the following:
<div data-ng-show="{{isHidden}}">
In this case, the value of the isHidden can be seen from the developer tools, and the rest of the expression does evaluates the same as that of (1).
<div ng-if="question.type =='options'" ng-repeat="option in question.options" >
<ion-radio name="{{$parent.question.id}}"
ng-model="$parent.question.answer"
required ng-value="option.id"
ng-class="{'has-custom-error':submitted && questionForm.{{$parent.question.id}}.$invalid,
'has-custom-success':questionForm.{{$parent.question.id}}.$valid }"
>
{{option.text}}
</ion-radio>
</div>
I have to add has-custom-error on user submitting the form without selecting the option.That is form is not valid but the ng-classis not getting evaluated.
The demo code is over here:http://plnkr.co/edit/FwjoCTYONvi3BoFHNKFK?p=preview
I don't think it is possible to use {{ }} expressions on a ng-class expression. You should be able to use it like this questionForm[$parent.question.id]
Also I never got ng-class working with classes with - between the parts, only CamelCase like hasCustomError. So {hasCustomError: questionForm.$invalid} should work.
Have you considered using the styleClass ng-invalid-required that is already used by angular for your styling? It is usually a lot cleaner, since there is no need for all the ng-class expressions
There is at least one problem with your code. You must not use interpolation {{}} within your ng-class attribute. Here is the correct syntax:
ng-class="{'has-custom-error':submitted && questionForm[$parent.question.id].$invalid, 'has-custom-success':questionForm[$parent.question.id].$valid }"
When you are inside an Angular expression, you don't need the mustache braces. So your code should be:
<div ng-if="question.type =='options'" ng-repeat="option in question.options">
<ion-radio name="{{$parent.question.id}}"
ng-model="$parent.question.answer"
required ng-value="option.id"
ng-class="{'has-custom-error':submitted && questionForm[$parent.question.id].$invalid,
'has-custom-success':questionForm[$parent.question.id].$valid }">
{{option.text}}
</ion-radio>
</div>
The variable form a.b has been replaced by the indexer form a["b"] so that it is evaluated correctly.
You can't use double-mustached expressions ({{ ... }}) inside expressions. The ng-class value is already an expression of type object, so you're supposed to use JavaScript syntax inside this attribute:
ng-class="{'has-custom-error': submitted && questionForm[$parent.question.id].$invalid,
'has-custom-success': questionForm[$parent.question.id].$valid }"
The use of $parent is also unecessary. BTW, you're not using it for your ng-repeat expression:
ng-repeat="option in question.options"
So you should simply use question instead of $parent.question: the scope of the ng-repeat block inherits from its parent scope, and the question is thus available through inheritance.
Note that, playing with your plunkr, it seems like the ion-radio directive that you're using doesn't correctly set the name attribute of the input it generates. This is probably why the CSS classes don't appear.
ng-form is the solution to my problem.But the problem that I am facing is in the name attribute of my ion-radio directive. For radio hence i used angular ng-invalid-required.And for other html tag i used ng-form.$invalid
I have an element:
I'd like to use
ng-class="{ 'children'+level.length }" (or something like this, i.e to output a class that has the number of levels. Is it possible to do it on this iterating element?
Yes, something like:
<div ng-repeat="level in levels">
<p ng-class="{'children' : level.length == 1}">test</p>
</div>
ng-class simply takes an expression.
I think the easiest way is to use a function in your ng-class.
$scope.levelClass = function(i){
return "level"+i;
}
and then
ng-class="levelClass(children.level)"
Check out this question for other solutions
Generating variable for ng-class dynamically using Expression in AngularJs
The Angular docs are really sparse on what is acceptable in an "expression" within a conditional ng-class.
For example, I'm running an ng-repeat over a list:
<ul class="clothes">
<li ng-repeat="piece in clothes | filter:query">
{{piece.name}}
</li>
</ul>
On every third <li> element I'd like to add a class of "third". Can this be done using ng-class with something like ng-class="{third : li:nth-child(3)}" or similar?
Side-note, is there a general reference somewhere that defines and gives examples of what can be used in an Angular expression? There's some really basic stuff that I can do with vanilla Javascript/css but I can't work out how to cram it into Angular!
Just create an expression that evaluates to true or false, a bit similar to Javascript expressions but with some differences, you can read about it here.
<ul>
<li ng-repeat="item in items" ng-class="{third: !(($index+1)%3) && !$first }">{{item}}</li>
</ul>
Here is a jsBin.
In my code I am telling ng-class to add the class 'third' when ($index+1)%3 is zero and it is not the $first list item ($index, $first and $last are created by ng-repeat).
if you want to use css instead of angular for the styling, you can use the css nth selector
http://www.w3schools.com/cssref/sel_nth-child.asp
li:nth-child(3n+3)
{
background:#ff0000;
}
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'">