ng-class multiple conditions - angularjs

I would like to apply multiple conditions into ng-class so the upper limit on 'u.Credit' will be let say 10000. Here is my code:
<tr ng-repeat="u in user.tables.tbl1" ng-init="u.DateAdded = JSONtoDATE(u.DateAdded)" ng-class='{lastRow : $last}' ng-model="myIndex = $index">
<td>{{u.ID}}</td>
<td>{{u.Name}}</td>
<td>{{u.Email}}</td>
<td>{{u.DateAdded}}</td>
<td ng-class='{selectedRow : u.Credit >= creditValue}'>{{u.Credit}}</td>
</tr>
... I have tried something like this but it didn't work:
<td ng-class='{selectedRow : ((u.Credit >= creditValue) && (u.Credit < 10000))}'>{{u.Credit}}</td>

You can replace that with a function call on your controller:
<td ng-class='getClassForCurrentRow(u)'>{{u.Credit}}</td>
I'm not sure what creditValue is and from where is populated, if it's from the controller then you don't need a new parameter, if not then add it to the function getClassForCurrentRow(u, creditValue).
And in your controller define the class:
{...}
$scope.getClassForCurrentRow = function(record) {
if (record.Credit >= $scope.creditValue) {
return "selectedRow";
}
return "";
}
Be careful to leave this function as simple as possible, because Angular runs it on every cycle to determine if something changed.

<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>

My apologize guys, I have made little mistake in tested code (I'm JS beginner) which had negative impact on desired functionality and after correcting it I have to say that expression I have claimed as 'not-working' is actually working:
selectedRow : (u.Credit >= creditValue && u.Credit < 10000)
However, your answers are very valuable to me as I'm learner. Thanks.

For multiple conditions in ng-class its better to create a function in controller that returns true or false for selectedRows in ng-class. like below:
{...}
$scope.getSelectedRow = function(record, creditValue) {
if ( record.Credit >= creditValue && record.Credit < 10000) {
return true;
}
return false;
}
Call this like:
<td ng-class='getSelectedRow(u,creditValue)'>{{u.Credit}}</td>

Try like below..
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<style>
.selectedRow{
color:#987789;
font-size:30px;
}
.unSelectedRow{
color:#234567;
font-size:30px;
}
</style>
<body ng-app="" ng-init="Credit = 10;creditValue=9;">
<p ng-class="{true: 'selectedRow', false: 'inactive'}[Credit >= creditValue]">Value : {{Credit}}</p>
<p ng-class="{false: 'unSelectedRow'}[Credit < creditValue]">Value : {{Credit}}</p>
</body>

Related

ng-class not working with ng-repeat

I have a situation where I have to add class according to the condition and the ng-class is working according to it even the condition in the ng-class is true.
<ul id="" class="clowd_wall" dnd-list="vm.cardData[columns.id].data"
dnd-drop="vm.callback(item,{targetList: vm.cardData[columns.id].data, targetIndex: index, event: event,item:item,type:'folder',eventType:'sort','root':'folder',current_parent:'folder'})" ng-model="vm.cardData[columns.id].data">
<div class="emptyCol" ng-if="vm.cardData[columns.id].data.length==0">Empty</div>
<li class="dndPlaceholder"></li>
<li class="cont____item" ng-repeat="card in vm.cardData[columns.id].data | orderBy:vm.sort" dnd-draggable="card"
dnd-effect-allowed="move"
dnd-allowed-types="card.allowType"
dnd-moved="vm.cardData[columns.id].data.splice($index, 1)"
dnd-selected="vm.tree.selected = card" ng-class="{emptyCard:card.data.length==0,zoomin:vm.zoomin=='zoomin',emptyCard:!card.data}">
<div class="item" style="height:79%">
<ng-include ng-init = "root = columns.id" src="'app/partials/card.html'"></ng-include>
</div>
</li>
</ul>
ng-class="{'emptyCard': (!card.data || !vm.cardData[columns.id].data.length),'zoomin':(vm.zoomin=='zoomin')}">
Seems like you want to use vm.cardData[columns.id].data.length instead of card.data.length
Your question is not clear as don't know what card.data will contain and ".data" will be present for each iteration
If it is array then this will work "card.data.length" and if there is no "data" key in "card" then ".length" will through error i.e. if card.data itself undefined then it will not have "length" property.
Try to add condition in ng-class one by one then you will be able to figure out which condition is causing problem.
Made some small change
ng-class="{emptyCard: card.data.length==0 || !card.data,zoomin: vm.zoomin=='zoomin'}"
If you have multiple expression, try old fashioned, if it looks best:
Controller:
$scope.getcardClass = function (objCard, strZoomin) {
if (!card.data) {
return 'emptyCard';
} else if (strZoomin =='zoomin') {
return 'zoomin';
} else if (card.data.length == 0) {
return 'emptyCard';
}
};
HTML:
ng-class="vm.getcardClass(card, vm.zoomin)"
NOTE: Replace vm with your controller object.

How to set a default value for AngularJS ng-repeat?

<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
I'm trying to set a default value for a status variable each time an ng-repeat loop occurs. I've tried ng-model, but that doesn't work. For instance,
I'd like to set isPageValid="true" before each time the ng-repeat loop runs. 'True' is will be the default value, and the validation function will test whether isPageValid should be set to 'false'.
I'd like the ng-repeat loop to run each time the ng-blur is exercised.
NOTE: I understand the way I'm using ng-model is incorrect, but this is just to illustrate the issue.
HTML:
<li ng-repeat="item in quantityList track by $index" ng-model="isPageValid='true'">
<input value="item.quantity" ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
JS:
scope.validateQuantity = function(item){
var qty = item.quantity;
if(parseInt(qty) >=1 && parseInt(qty) <= 200){
item.isQuantityValid = true;
}else{
item.isQuantityValid = false;
scope.isPageValid = false;
}
}
The loop creates a list of input boxes. The objective is to create a global validation value called isPageValid which is 'false' if the validation by the JS fails for any input box. Note, when ng-blur is exercised, the JS validation runs and loop should re-run.
I believe ng-init could help...
<ul ng-init="isPageValid='true'">
<li ng-repeat="item in quantityList track by $index" >
<input ng-blur="validateQuantity(item)" ng-model="item.quantity">
</li>
</ul>
Note that it would be better practice to initialise isPageValid in the controller that is in the same scope as your validateQuantity function.
Here is an example of how you could initialise isPageValid in your controller and update the value after each call to validateQuantity...
In your controller:
scope.isPageValid = true;
function updatePageValid() {
scope.isPageValid = scope.quantityList.every(item => item.isQuantityValid);
}
scope.validateQuantity = function(item) {
var qty = parseInt(item.quantity);
item.isQuantityValid = (qty >= 1 && qty <= 200);
updatePageValid();
});

AngularJS - how to highlight/add class to a max value

Let say I have a very simple data that Im looping through with ng-repeat.
Now, how can I highlight (add a css class) to a highest value in the data.
Data:
$scope.marks = [
{point:'11'},
{point:'2'},
{point:'23'}
];
html:
<ul>
<li ng-repeat="value in marks" class={{here add class for value 23}}> //how to add class to li with max value, in this case it is 23
{{ value.point}}
</li>
</ul>
Many thanks for your help
PLUNKR
You can use calculate the max value in a watch:
$scope.$watchCollection('marks', function(items) {
$scope.maxPoint = -1; // assuming we won't have negative values
angular.forEach(items, function(item) {
if (parseInt(item.point) > $scope.maxPoint) {
$scope.maxPoint = item.point;
}
});
});
Then use ngClass directive in your markup:
<li ng-repeat="value in marks" ng-class="{max : value.point == maxPoint}">
{{ value.point}}
</li>
Like Petr pointed out this won't perform well. Calculating the max value on changes is a better way. Here's a working plunk : http://plnkr.co/edit/F8yjoWR0ZWVF4tcck1rH?p=preview

Is it possible to turn a filter on and off conditionally in AngularJS?

For example I have a table in which I am showing students marks of Math, Science, English and other subjects. And I have a checkbox which if checked will only list the students that have {{student.mathMarks + student.scienceMarks > 150}} (i.e. sum of student's math and science marks to be more than 150). And when the checkbox is unchecked it will again show all the students. Is there a way I could associate a conditional filter with the given students with ng-repeat to achieve this?
Following is the code relating to the case I tried explaining above:
<tr ng-repeat="student in students">
<td >
{{student.name}}
</td>
<td >
{{student.mathMarks}}
</td>
<td >
{{student.scienceMarks}}
</td>
<td >
{{student.englishMarks}}
</td>
</tr>
<input type="checkbox" ng-model="onlyFooStudents" />
You can pass a function as the expression for you filter. So in that case all you got to do is to declare a function in your scope that checks for the flag, something like:
$scope.yourCustomFilter = function(student) {
// if flag is false, bring everybody. if not, bring only the ones that match.
return $scope.onlyFooStudents ||
student && student.mathMarks + student.scienceMarks > 150;
};
And in your binding you will have ng-repeat="student in student | filter:yourCustomFilter".
Another way to implement it in case you're using the same filter somewhere else, is to create a custom filter and you can than pass in parameters, something in these lines:
angular.module('appFilters', []).filter('filterStudents', function() {
function isApproved(student) {
return student && student.mathMarks + student.scienceMarks > 150;
}
return function(students, showApprovedOnly) {
// if it is to bring everybody, we just return the original array,
// if not, we go on and filter the students in the same way.
return !showApprovedOnly ? students : students.filter(isApproved);
// COMPATIBLITY: please notice that Array.prototype.filter is only available IE9+.
};
})
Your binding you then be ng-repeat="student in students | studentFilter:onlyFooStudents". Notice that we pass in the onlyFooStudents as an argument to your filter, bound directly from the scope.
Create a filter that will receive an extra argument (that of the checkbox) to know when to conditionally enable/disable the filter.
function FooFilter() {
return function(data, isEnabled) {
var result = [];
if (angular.isArray(data) && isEnabled) {
angular.forEach(data, function(student) {
if (student.mathMark + student.scienceMark > 150) {
result.push(student);
}
});
return result;
} else {
return data;
}
}
}
<tr ng-repeat="student in students | fooFilter : filterState">
<td>...</td>
</tr>
...
<input type="checkbox" ng-model="filterState" /> Enable filter
Here is a working plunker.

How to ng-repeat into html table with multiple levels of json?

I have an object of social media stats. I'm trying to ng-repeat them into a table. Here's my plunker.
HTML:
<table>
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td>{{metricData}}</td>
</tr>
</table>
Controller object:
$scope.data = { buzz:0,
Delicious:121,
Facebook:
{
like_count: "6266",
share_count: "20746"
},
GooglePlusOne:429,
LinkedIn:820,
Twitter:4074
};
I run into a problem when I get to the Facebook results. Within the <td> that entire object gets displayed (as it should be with how I have my code setup). But what I'd rather have happen is to repeat through that object and display the key and value in the cell.
I tried doing something looking to see if metricData is an object and doing some sort of ng-repeat on that. But I wasn't having luck with that. Any idea on how I can display the inner object (keys & value) within the cells?
You can define a scope function returning the type of metricData :
$scope.typeOf = function(input) {
return typeof input;
}
And then you can display it according to its type :
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td ng-switch on="typeOf(metricData)">
<div ng-switch-when="object">
<div ng-repeat="(key, value) in metricData">
<span>{{key}}</span>
<span>{{value}}</span>
</div>
</div>
<span ng-switch-default>{{metricData}}</span>
</td>
</tr>
You can see it in this Plunker
Sounds like you'll need a specific directive that wires up children to be recursive, take a look at this example: Recursion in Angular directives
What you'd check on is if what you need to repeat is an object and not a value, then add the new element compile it, and start the process over again.
I'm assuming you want each of those values to have their own line but you don't explain exactly how you want it to work. I think the matter would best be handled by passing a clean version of what you want to the ng-repeat directive. I'm assuming you want two rows for facebook in your sample. You could create a filter to flatten the metrics so there are properties "Facebook_like_count" and "Facebook_share_count" (PLUNKER):
app.filter('flatten', function() {
function flattenTo(source, dest, predicate) {
predicate = predicate || '';
angular.forEach(source, function(value, key) {
if (typeof(value) == 'object') {
flattenTo(value, dest, predicate + key + '_');
} else {
dest[predicate + key] = value;
}
});
}
return function(input) {
var obj = {};
flattenTo(input, obj, '');
return obj;
}
});
Then your repeat can use the filter:
<tr ng-repeat="(metric, metricData) in data|flatten">

Resources