AngularJS ng-class multiple conditions with OR operator - angularjs

I try to find out the good syntax for adding classes depending on angular values.
I want to activate a class regarding 2 conditions (one on live user changes, and one on loading datas) with a OR operator.
Here is the line :
<a href="" ng-click="addFavorite(myfav.id);favorite=!favorite">
<i class="fa orange" ng-class="{'fa-star': (favorite || (fav==myfav.id)), 'fa-star-o': !favorite}"></i>
</a>
I tried some different codes like this one :
ng-class="{'fa-star': favorite, 'fa-star': (fav==myfav.id), 'fa-star-o': !favorite}"
without any success.
Can someone help me finding the good syntax ?

Try this.
<a href="" ng-click="addFavorite(myfav.id);favorite=!favorite">
<i class="fa orange" ng-class="{'fa-star': favorite || fav==myfav.id, 'fa-star-o': !favorite}"></i>
No need the brackets.

Once you have to add some logic behind ng-class it's always better to stick to using the controller to do that. You can do it two of either ways: JSON syntax (same as in your HTML, just more readable) or obviously JavaScript.
HTML (JSON) Syntax
HTML
<i ng-class="getFavClassIcon(myFav.id)"></i>
JS
$scope.getFavClassIcon= function (favId) {
return {
'fa-star-o' : !$scope.favorite,
'fa-star' : $scope.favorite || $scope.fav === favId
};
};
Good Old IF-statement (JavaScript)
HTML
<i ng-class="getFavClassIcon(myFav.id)"></i>
JS
$scope.getFavClassIcon= function (favId) {
if (!$scope.favorite) {
return 'fa-star-o';
} else if ($scope.favorite) { // obviously you can use OR operator here
return 'fa-star';
} else if ($scope.fav === favId) {
return 'fa-star';
}
};

The HTML will remain the same
<a href="" ng-click="addFavorite(myfav.id);favorite=!favorite">
<i ng-class="{'fa-star-o':!favorite,'fa-star':favorite||fav===myfav.id}"></i>
</a>
But the order in which classes are present in your CSS file will matter
The fa-star class will apply either when favorite is true or fav===myfav.id returns true.
Therefore if after clicking once , suppose fav===myfav.id returns true and keeps on returning true , even when clicking again , then the class fa-star will be applied always from then on.
If by default favorite is false , then fa-star-o will be applied when template is loaded the first time, but after the first click ,when favorite is set to true , it will get removed. Then on second click , when favorite is set to false again , fa-star-o it will get applied but in this case , fa-star class will also be applied as fa===myfav.id condition would be still returning true (Assuming that is the case).
Therefore you will need to prioritize which class needs to get applied for sure when it is present on the element as case can arise when both classes can be present at the same time on the element. For example if fa-star-o class takes higher priority, then put it below the fa-star in your CSS , like for example
.fa-star {
border: 1px solid #F00;
}
.fa-star-o {
border: 1px solid #000;
}
See working demo at http://plnkr.co/edit/Dh59KUU41uWpIkHIaYrO?p=preview

You can use expression with ng-class
<i class="fa orange" ng-class="favorite || fav == myfav.id ? 'fav' : 'no-fav'"></i>

For example:
In my scenario i need to apply uppercase class in some condition and in some condition i do not need to apply that uppercase class.
inputTextCapitalSmall(assetId) {
return {
'uppercase': assetId !== 'TELEKURS' && assetId !== 'REUTERS' && assetId !== 'S&P',
};
}
<form [formGroup]="querySearchForm" >
<input autocomplete="off" matInput id="assetIdTypeValue" [ngClass]="inputTextCapitalSmall(querySearchForm.value.assetIdType)" >
</form>

Related

AngularJS - How to correctly use ng-show inside a ng-repeat? My boolean isn't getting updated

I have a ng-repeat that loops over 9 divs, each one has a different color.
When the user clicks on one div, its color it's gonna be the background color of a section.
I'm trying to do this:
The array that gets repeated is structured like this:
interface colorBoxes {
color: string;
isSelected: boolean;
}
in the view:
<div ng-repeat="s in vm.colorBoxes track by $index">
<div class="pointer" ng-click="w.backgroundColor = s.color; vm.pickColor(s, $index)" ng-style='{"background-color": s.color}'>
<i ng-show="vm.isColorSelected($index) === true" class="fa fa-check fa-1x checkOnSelectedLegend"></i>
</div>
</div>
in the controller:
pickColor(array: any, index: number) {
for(var i = 0; i<=this.colorBoxes.length; i++) {
this.colorBoxes[i].isSelected = false;
}
array[index].isSelected = true;
}
I use this function so when you click on a DIV, its variable: isSelected gets true, and all the other DIV's have theirs set to false.
I use this variable in the view with a ng-show, to show a check mark on the DIV that is currently selected, but this isn't working, below the function I put in that ng-show
isColorSelected(index:number):boolean {
return this.colorBoxes[index].isSelected
}
What am I doing wrong?
To summarize, I want that when you click on a box, its color string gets applied to another element (that is working correctly with my code), then, that box need to have a check mark appear on top of it, I tried with the above functions, by setting the isSelected var to true when clicked, but it doesnt work.
I'm pretty sure the problem is that angular isn't checking for changes in that ng-show, I just don't know exactly how to make it check for changes, and maybe there is a cleaner way to obtain what I'm trying to do!
Thank you
addded fiddle: http://jsfiddle.net/7zymp2gq/1/
Ok, here you have your code fixed and working:
http://jsfiddle.net/7zymp2gq/4/
Basically there were 2 things wrong with the function $scope.pickColor:
The loop was entering into not existing fields, I have changed the <= with a <
It was updating array[index], and it should be updating $scope.colorBoxes[index]
Instead of using function at ng-show you can use the isSelected property:
<div ng-app="app" ng-controller="Ctrl">
<div class="class1" ng-repeat="s in colorBoxes track by $index">
<div class="pointer class2" ng-click="pickColor(colorBoxes,$index);" ng-init="lastselected=s.isSelected?$index:null" ng-style='{"background-color": s.color}'>
<i ng-if="s.isSelected" class="fa fa-check fa-1x checkOnSelectedLegend"></i>
</div>
</div>
<div class="changeColor" ng-style='{"background-color": chosenColor}'></div>
</div>
Check this demo.

"Use expression as" in ng-repeat

Building a table I am deep within nested ng-repeats.
Depending on a scope variable I have to display/use a different field from my objects.
Is there a shorter way to adress the decision/field call in a way that could look like 'from now on use expression as myVar'?
Currently my code looks very ugly and basically always repeating a pattern like direction==='sources' ? connection.target.X : connection.source.X
As I am already pretty deep I cannot simply rearrange my array in Controller first.
This is just a small part of it:
<strong>{{direction==='sources' ? connection.target.name : connection.source.name}}</strong>
<br>
<a ng-click="goToEntityUsingReport(direction==='sources' ? connection.target.id : connection.source.id)">
<i class="fa fa-plus-square-o"></i>
</a>
<a ng-show="hasFurtherConnections(direction==='sources' ? connection.target.id : connection.source.id)" ng-click="setEntityFocus(direction==='sources' ? connection.target.id : connection.source.id)">
<i class="fa fa-chevron-circle-right"></i>
</a>
{{getEntityTotal(direction==='sources' ? connection.target.id : connection.source.id) | acCurrency}} total)
You can assign this expression on the return statement of a function in your controller in order to look cleaner.
e.g.
$scope.getValueBasedOnProperty(connection, prop) {
if($scope.direction === 'sources') {
return connection.target[prop];
}
else {
return connection.source[prop]
}
}
Then in the view:
<strong>{{getValueBasedOnProperty(connection, 'name')}}</strong>
<br>
<a ng-click="goToEntityUsingReport(getValueBasedOnProperty(connection, 'id')">
<i class="fa fa-plus-square-o"></i>
</a>
<!-- And goes on ... -->

Angular - Should ngDisabled work on any HTML item?

In my angular app i have a flag icon using the code:
<i ng-click="detail.flag()" class="fi-flag"></i>
I also have a boolean variable that I'd like to use to disable this.
I've tried the following to no avail:
<i ng-disabled="showDuplicate" ng-click="detail.flag()" class="fi-flag"></i>
and
<div ng-disabled="showDuplicate"><i ng-click="detail.flag()" class="fi-flag"></i></div>
Any ideas why they dont work?
Thanks.
ngDisabled - This directive sets the disabled attribute on the element if the expression inside ngDisabled evaluates to truthy.
Elements that can receive the disabled attribute include <button>, <input>, <textarea>, <optgroup>, <option> and <fieldset>.
That's why it won't work on <i> (or <div>) element.
DEMO
As others mentioned, ng-disabled is specific for some tags only. I assume that you want to disable clicking on the element when your variable is false, you can do it this way
<i ng-click="showDuplicate && detail.flag()" class="fi-flag"></i>
This is called short circuiting an expression, if showDuplicate is true, the next term will be evaluated which is detail.flag() if it is false, it will not continue evaluating the next term since false && true is still false so it will not bother evaluating the next terms
Though you should be styling the element if you disable something, so you should add a class that says it is disabled and style it accordingly
<i ng-class='{disabled: showDuplicate}' ng-click="showDuplicate && detail.flag()" class="fi-flag"></i>
in your css:
.disabled{
cursor: not-allowed;
opacity: 0.8 /* ? it's up to you how you want to style it*/
}
The answer is correct, you cannot use ng-disable with icon html tag.
I tried somthing like that:
<div ng-controller="DemoController as detail">
<i ng-disabled="detail.showDuplicate" ng-click="detail.flag()" class="fa fa-flag">test</i>
<button ng-disabled="detail.showDuplicate" ng-click="detail.flag()" class="fa fa-flag"></button>
</div>
https://plnkr.co/edit/0DBXJ4o9hmdtep8PM4Wc?p=catalogue
I hope it helps.

angularjs how to trigger changes on object in scope

I have the $scope object (array of objects) like this
$scope.parts = [];
(content of $scope.parts is changing during 'run-time', not just filled once per page load)
Later, it some custom directive i show those parts in such manner:
<li ng-repeat="part in parts">
<span>{{part.name}}
<i class="fa fa-check"
tooltip="some tooltip"
...
</i>
</span>
</li>
According to some logic, i want to change 'fa-' class and tooltip text.
I can do it like this
<i class="fa"
ng-class="haveDescr(part.name)"
//and in directive's controller
$scope.haveDescr = function (partName) {
return someCondition ? 'fa-check' : 'fa-question-circle';
};
and so on for the tooltip, and... for every attribute i want to change?
Is there a better way, than to write a scope "check-function" for every attribute? How can i trigger changes in every single part/property of $scope.parts and do the DOM changes described above? What is the right "angular way" for this? Or, maybe it is possible to 'intercept' ng-repeat action and do everything there?
You can use ng-class with an 'object' expression.
<i class="fa" ng-class="{'fa-check' : part.name, 'fa-question-circle' : !part.name}">
You can use ng-class and title
<i ng-class="{'fa-check':showFaCheck(part.name), 'fa-question': !showFaCheck(part.name) }" title="{{getTooltip(part.name)}}"/>
Fiddle http://jsfiddle.net/4PYZa/303/

How to create dynamic expression in ng-class

I have a ngRepeat element that has a delete button that triggers a confirmation message. I'm trying to make the confirmation message show with a dynamic expression like so:
<div ng-repeat="item in items">
<a ng-click="delete(item_id)"></a>
<span ng-class="{'show':'delete_'+item._id}">Are you sure you want to delete your review? </span>
</div>
Unfortunately I can't get the expression 'delete_'+item._id to show up in the ngClass directive. Can someone please offer a solution?
Using ng-class="{'show': 'delete_' + item._id}" will add the class show whenever the expression 'delete_' + item._id' evaluates to true (which is always). You probably want to have an expression next to show which is true when the user has clicked the a tag, i.e. ng-class="{'show': userWantsToDelete(item)}".
Additionally, if you want to add the class 'delete_' + item._id to the element, you can use angular expressions with class attribute, i.e., class="{{'delete_' + item._id}}" on the element.
try this one.
<a ng-click="delete = !delete">delete</a>
<span ng-class="{show: delete}">Are you sure you want to delete your review? </span>
if you want to show one delete confirmation message of last clicked <a>
In view
<a ng-click="delete(item._id)">delete</a>
<span ng-class="{show: item._id==delete_id}">Are you sure you want to delete your review? </span>
In controller
$scope.delete = function(id) {
$scope.delete_id = ($scope.delete_id == id) ? !id : id;
}

Resources