Conditional ng-class - angularjs

I'm trying to use ng-class with a condition, like this:
<li ng-repeat="time in matter.times_hourly | filter:searchText" ng-class="{'time.write_off_class' : time.write_off === true, 'time.narrativeState' : time.write_off === false}" >
time.write_off_class has two classes inside it called "write_off_bg time_closed".
time.narrativestate has one class inside it called "time_closed"
time.write_off is a boolean.
So, I think my problem are the quotation marks.
I'm not sure where to put them, so I tried every possibility:
Quotes on condition:
`ng-class="{time.write_off_class : 'time.write_off === true', time.narrativeState : 'time.write_off === false'}"`
Result: Angular error.
`angular.min.js:107 `Error: [$parse:syntax] http://errors.angularjs.org/1.4.5/$parse/syntax?p0=.&p1=is%20unexpected%2C%…20%3D%3D%20true'%2C%20time.narrativeState%20%3A%20'time.write_off%20%3D%3DNaNalse'%7D&p4=.write_off_class%20%3A%20'time.write_off%20%3D%3D%20true'%2C%20time.narrativeState%20%3A%20'time.write_off%20%3D%3D%false'%7D
No quotes:
ng-class="{time.write_off_class : time.write_off === true, time.narrativeState : time.write_off === false}"
Result: Angular Error.
angular.min.js:107 Error: [$parse:syntax] http://errors.angularjs.org/1.4.5/$parse/syntax?p0=.&p1=is%20unexpected%2C%…f%20%3D%3D%20true%2C%20time.narrativeState%20%3A%20time.write_off%20%3D%3DNaNalse%7D&p4=.write_off_class%20%3A%20time.write_off%20%3D%3D%20true%2C%20time.narrativeState%20%3A%20time.write_off%20%3D%3D%false%7D
Quotes on everything (class and condition):
ng-class="{'time.write_off_class' : 'time.write_off === true', 'time.narrativeState' : 'time.write_off === false'}
Result: No error, but the element gets both classes, write_off_class AND narrativeState.
Quotes on classes :
ng-class="{'time.write_off_class' : time.write_off === true, 'time.narrativeState' : time.write_off === false}
Result: No error, and apparently the element gets the correct class (in this case, narrativeState, because at the beginning of the code all time.write_off are set to FALSE) BUT the element gets no style. If i put just ng-class="time.narrativeState" everything's ok, but if it gets it through the ng-class, then it is not working.
What am I doing wrong? Is there any reason for the element not styling through a condition with 'time.narrativeState' even when I'm sure it works by itself?
I've been trying more things and I know where the main problem is now, still cannot solve it.
My object 'time' has two fields inside that I use to give styling classes to some elements.
"time.narrativeState" has, for example, the class "time_closed" on it.
The thing is that, when I write ng-class="time.narrativeState" and I go to see the element's style, I can see "time_closed" BUT if I use instead the condition I was talking about in this question ng-class="{{ time.write_off ? time.write_off_class : time.narrativeState }}" > what the element gets as style is not "time_closed" it is literally "time.narrativeState" and because time.narrativeState is not a class but a object's field, it dosen't work.
Why it is getting "time.narrativeState" as the class and it's not looking INSIDE time.narrativestate to get the correct class "time_closed"???

You can use ternary operator inside simple interpolation tags:
ng-class="{{ time.write_off ? time.write_off_class : time.narrativeState }}"

Related

Add css class when user logged ng-class

How can I use ng-class to add a Css class where I put display: none; when the user is log in?. I'm using mean.js so I first tried using
ng-show="authentication.user"
But that only makes the element to hide like visivility : hidden;
Besides I need to add other classes in elements that i keep rather if the user is logged or not where I change margins and other stuff.
I tried using in angular a condition:
$scope.logged = false;
if ($scope.authentication.user) {
$scope.logged = true;
}
and then adding the ng-class condition like this:
ng-class="logged ? 'myClass1' : 'myClass2'"
But it failed, what am I doing wrong?
ng-if="authentication.user"
will remove the element altogether unlike ng-show which hides it.
With AngularJS, the right syntax is :
ng-class="{ className : Boolean}"
A example with multiple classes from AngularJS documentation :
ng-class="{strike: deleted, bold: important, 'has-error': error}"
Or with a function :
ng-class="{ invalid : !form.validPassword()}"
Hope this will help.

AngularJS data-binding

I have two code examples that work good, but I don't understand the difference.
So, the first is:
AngularJS:
$scope.state = {presentation: true};
HTML:
<div ng-class="{{state.presentation}} ? 'on' : 'off'"></div>
And the second one:
AngularJS:
$scope.presentation = true;
HTML:
<div ng-class="presentation ? 'on' : 'off'"></div>
Why can't I use something like this in the 2-nd example:
<div ng-class="{{presentation}} ? 'on' : 'off'"></div>
When I use {{ }} with $scope.presentation = true; it doesn't work in ng-class, but I can use {{presentation}} like the text, I mean <div>{{presentation}}</div> and it works good. Why?
But with $scope.state = {presentation: true}; I can use {{presentation}} even in ng-class and it works good.
What the difference?
You should'nt use an expression inside a ng-attribute like that. And it will fail (without or without the state object) :
Error: [$parse:syntax] Syntax Error: Token '?' not a primary
expression at column 2 of the expression [ ? 'on' : 'off'] starting at
[? 'on' : 'off'].
That's normal because angularJs executes it as an angularJS expression, so when you're typing :
<div ng-class="presentation ? 'on' : 'off'"></div>
Internally angularJS executes it as an expression and it can be written also like that :
<div class="{{presentation ? 'on' : 'off'}}"></div>

Difficulty adding multiple classes wit ng-class

I'm trying to add two classes to this div using ng-class, but even though checkForActive is returning true, it's being ignored and only class_{{$index}} is getting added.
If I remove class_{{$index}} altogether, active is added correctly.
Is there an obvious mistake in my syntax here?
<div "ng-class="{active: checkForActive, disabled: checkForDisable, class_{{$index}}} "></div>
You could just provide true value to the key class_{{$index}} just to that property gets added as a class name to the class list of the element. It is just the way you do active: checkForActive.
i.e
{active: checkForActive, disabled: checkForDisable, class_{{$index}} :true}
But i believe there could be some undesired behavior due the usage of interpolation ({{) within the ng-class directive (Atleast used to happen with older versions). So you could as well use an array.
ng-class="[checkForActive && 'active' , checkForDisable && 'disabled', 'class_' + $index]"
The above method will add a class name false if active or disabled is false, which should be harmless.
Or pass index to a controller function say getStatus($index) and return the object from there and use it in the ng-Class directive.
$scope.getClass = function(){
var obj = {active: $scope.checkForActive, disabled: $scope.checkForDisable};
obj['class_' + this.$index] = true;
return obj;
}
and
ng-class="getClass()"
#Okazari pointed out that it indeed works by mixing class with ng-class so you could also do:
class="class_{{$index}}" ng-class="{active: checkForActive, disabled: checkForDisable}"

ngClass string binding expression with class map

Is it possible to use ngClass with an expression AND a class map? I want to conditionally add a class based on the existence of a variable as well as use that variable in the expression that creates the class.
For instance, if isActive() is true and getStatus() returns "valid" I want the class list to be "element element--active element--valid". If getStatus() returns undefined I want the class list to be "element element--active".
<div
class="element"
ng-class="{
'element--active': ctrl.isActive(),
'element--{{ ctrl.getStatus() }}': ctrl.getStatus()
}"></div>
Doesn't seem to work.
<div
class="element element--{{ctrl.getStatus()}}"
ng-class="{
'element--active': ctrl.isActive()
}"></div>
Works but then there's an extra hanging "element--" if getStatus() returns undefined.
Do I have to add a method in my controller to handle the class generation?
i'd suggest to make just one function call to get the classes. It will make it cleaner and have the class logic in one place.
In your controller:
this.getElementStatus = function(){
var rules = {active:this.isActive()}; //Prefix with element-- {element--active:}
rules[this.getStatus()] = true; //Prefix with element--, rules['element--' + this.getStatus()] = true
return rules;
}
and your view would just be:
<div
class="element"
ng-class="ctrl.getElementStatus()"></div>
It seems like your element-- is redundant with the rule instead make use of cascadeability(CSS) property. and define rules as :
Example:
.element.active{ /*....*/ }
.element.success {/*...*/}
.element.error{/*...*/}
This will help in maintenance, gets more verbose and get to the natural way of adding css rules and could remove these kind of complexities from the view.
You could as well do:
<div class="element"
ng-class="{'active': ctrl.isActive(), '{{ctrl.getStatus()}}':true}"
or :
<div class="element"
ng-class="[ctrl.isActive() ? 'active' : '', ctrl.getStatus()]"
If you don't mind getting a true added as a rule(should not affect anything anyways) then,
<div class="element"
ng-class="[!ctrl.isActive() || 'element--active' , 'element--' + ctrl.getStatus()]">
You can use class and ng-class map on the same element. But since your class name is dynamic you will have to something like this.
<div
ng-class="'element '
+ (ctrl.isActive() ? ' element--active' : '')
+ (ctrl.getStatus() ? ' element--' + ctrl.getStatus() : '')"></div>

How to access an attribute in a template, besides by its name?

In an underscore template, is there any other way to access an attribute besides by its name? I've got one called "2a" and I cannot reference it directly, due to its first character being a number. For example, this doesn't work:
<input type="checkbox" name="6a" <%= 6a ? "checked" : "" %>>
Thanks!
You have a few options other than renaming the offending attribute.
Underscore's _.template has a variable option:
By default, template places the values from your data in the local scope via the with statement. However, you can specify a single variable name with the variable setting.
So you could do this:
<input type="checkbox" name="6a" <%= v['6a'] ? "checked" : "" %>>
and this:
var t = _.template($('#whatever').html(), null, { variable: 'v' });
var h = t({ '6a': true });​
Demo: http://jsfiddle.net/ambiguous/hBhfu/
You could also wrap it manually when you call the template function:
t({ v: { '6a': true }});
You'd use the same template as above in this case.
Demo: http://jsfiddle.net/ambiguous/8AZKw/

Resources