break a forEach with angularJS - arrays

I need some help. I have 2 loops to traverse two lists of records . The thing is that at some point should put a break or something, because the last loop crushes the value I'm looking for.
This is my code
for (var i in $scope.users) {
for (var j in $scope.states) {
if ($scope.users[i].id === $scope.states[j].user) {
if ($scope.states[j].estado === 'totallyBussy') {
$scope.users[i].estado= 'Not available';
} else if ($scope.states[j].estado === 'partlyBussy') {
$scope.users[i].estado= 'Maybe available';
}
}
else {
$scope.users[i].estado= 'Available';
}
}
}
Where user 4 and user 5 should be 'Maybe available' and 'Not available', but with this code, I'm getting 'Available for user 0, 1, 2, 3, and the last one. And the last one is crushes with else.
I hope I explained well.
Thanks so much

You can use the break keyword, which will end the loop when executed.
One side note: you don't want to use for (var i in array) {} since you may iterate through Array properties (and have i take unexpected values).
I updated your code with a more reliable iteration.
for (var i = 0, il = $scope.users.length; i < il; i++) {
var user = $scope.users[i];
for (var j = 0, jl = $scope.states.length; j < jl; j ++) {
var state = $scope.states[j];
if (user.id === state.user) {
if (state.estado === 'totallyBussy') {
user.estado = 'Not available';
} else if (state.estado === 'partlyBussy') {
user.estado = 'Maybe available';
}
// Go to the next user (break the "states" loop)
break;
} else {
user.estado = 'Available';
}
}
}
EDIT: If $scope.users and $scope.states are not Arrays but actually Objects (which would seem strange to me but anyway), you can keep for (var i in object) {} but you have to add a check: if (object.hasOwnProperty(i)) {} in the loop.

you can add a flag which will become true when you got your desired value.
something like
var gotValue = false;
for (var i in $scope.users) {
if(!gotValue)
{
for (var j in $scope.states) {
if ($scope.users[i].id === $scope.states[j].user) {
if ($scope.states[j].estado === 'totallyBussy') {
$scope.users[i].estado= 'Not available';
gotValue = true;
} else if ($scope.states[j].estado === 'partlyBussy') {
$scope.users[i].estado= 'Maybe available';
gotValue = true;
}
}
else {
$scope.users[i].estado= 'Available';
gotValue = true;
}
}
}
}

In AngularJS, there is no break for loops,etc., so one has to go with logic manually.
A similar case has been demonstrated here.
Here, I have created a variable f, which has been set to false initially. On forEach loop, based on a condition, it is made to true, further which it works as break.
Please find the code below:
HTML:
<div ng-app="app" ng-controller="test"></div>
JS:
var app = angular.module('app',[]);
app.controller ('test', function ($scope){
var f = false;
angular.forEach([1,2,3,4,5], function(v,k){
if(k > 2){
f = true;
}
if(!f) {
document.write('value = ' + v + ' <br>');
}
});
});

Related

AngularJS multiselect custom filter not working as intended

In an AngularJS record display (with filters) I have a multiselect array of territories that a user can select from to find out if a certain item is available in a certain territory.
The array returns a list of values such as
['001','010','200']
based on the ID of the territories selected. This is then checked against a JSON list of records which has a JSON value looks like this
territoriesnotavailable: "001, 085, 090"
Each record either has this set to null, or has a list from one to many numbers.
I currently use the following code (customFilter) which works perfectly if you only select ONE value.. it basically makes the item filter out if the territory selected in the multiselect is in the list of territoriesnotavailable
function CustomTerritoryFilter() {
return function(data, query) {
if (query.length === 0) return data;
if (data) return data.filter(function(item) {
for (var i = 0; i < query.length; i++) {
var queryitem = query[i]["id"];
if(item.territoriesnotavailable) {
stringB = item.territoriesnotavailable;
} else {
stringB = 'xxxxxxxx';
}
stringA = queryitem;
if (!(stringB.indexOf( stringA ) > -1)) {
return data;
}
}
});
return [];
};
}
So if I choose only one filter (resulting in a query of ['010'] for example. and this appears in territoriesnoavailable for the record.. it vanishes as expected.. but if I choose any value that is NOT in territoriesnotavailable the item appears again.. i need the record to vanish if ANY selected territory appears in the list regardless of any that do not
function CustomTerritoryFilter() {
return function(data, query) {
if (query.length === 0) return data;
if (data) return data.filter(function(item) {
for (var i = 0; i < query.length; i++) {
var queryitem = query[i]["id"];
if(item.territoriesnotavailable) {
stringB = item.territoriesnotavailable;
} else {
stringB = 'xxxxxxxx';
}
stringA = queryitem;
if (!(stringB.indexOf( stringA ) > -1)) {
return false;
}
}
return true;
});
return [];
};
}
This is the code that I settled on. It basically sets a flag as 1 (show) and then checks each number in the filter.. if there is just one occurance of the number in the list, the flag is set to zero. At the end of the check data is shown if the flaG REMAins as 1
function CustomTerritoryFilter() {
return function(data, query) {
if (query.length === 0) return data;
if (data) return data.filter(function(item) {
var flag = 1;
for (var i = 0; i < query.length; i++) {
var queryitem = query[i]["id"];
if(item.territoriesnotavailable) {
stringB = item.territoriesnotavailable;
} else {
stringB = 'xxxxxxxx';
}
stringA = queryitem;
if (stringB.indexOf( stringA ) > -1) {
flag = 0;
}
}
if(flag === 1) {
return data;
}
});
return [];
};
}

how to check a value in array object angularjs

i have this array object:
$scope.datas.labels=['10','20','30']
and also i have a function return an array object like this:
response.labels=['10','20','30','50','100','80']
i created a function which recieve the last result..but what i want is to check if a value in response.labels exists in the $scope.datas.labels i dont want to insert it..to avoid duplicated data in $scope.datas.labels, how i can do that??
i tried this but i didnt work:
$scope.concatToData=function (response) {
if($scope.datas.labels=='') {
$scope.datas.labels = $scope.datas.labels.concat(response.labels);
}else {
var i;
for (i = 0; i < $scope.datas.labels.length; i++) {
alert('qa' + JSON.stringify($scope.datas.labels));
alert('res' + JSON.stringify(response.labels));
if ($scope.datas.labels[i] !== response.labels[i]) {
$scope.datas.labels = $scope.datas.labels.concat(response.labels[i]);
} else {
break;
}
}
}
$scope.datas.datasets = $scope.datas.datasets.concat(response.datasets);
}
Try this it will work as per your expectation and requirement.
var arr1=['10','20','30'];
var arr2=['10','20','30','50','100','80'];
for (var i in arr2) {
if(arr2[i] != arr1[i]) {
arr1.push(arr2[i]);
}
}
document.getElementById('result').innerHTML = arr1;
#result {
font-weight:bold;
}
<div id="result"></div>
Take a look at the lodash library, you'll find it useful, and this will be useful for you too:
let common = _.intersection($scope.datas.labels, response.labels);
if (_.size(common) && _.includes(common, 'myValue')) {
// You have a winner;
// This item (myValue) is in both;
} else {
}
Hope that helps.
You can also try that:
var response = ['foo', 'fabio'];
var labels = ['foo'];
var result = response.filter((value) => {
return labels.filter((rs) => {
return rs == value;
}).length == 0;
});
It will return only the data that does not exists on $scope.datas.labels.

checkbox filter for json array in Angularjs

I have create a filter but this filter is not working with array inside array.
'http://plnkr.co/edit/oygy79j3xyoGJmiPHm4g?p=info'
Above plkr link is working demo.
app.filter('checkboxFilter', function($parse) {
var cache = { //create an cache in the closure
result: [],
checkboxData: {}
};
function prepareGroups(checkboxData) {
var groupedSelections = {};
Object.keys(checkboxData).forEach(function(prop) {
//console.log(prop);
if (!checkboxData[prop]) {
return;
} //no need to create a function
var ar = prop.split('=');
//console.log("ar is - "+ar);
if (ar[1] === 'true') {
ar[1] = true;
} //catch booleans
if (ar[1] === 'false') {
ar[1] = false;
} //catch booleans
/* replacing 0 with true for show all offers */
if(ar[0]=='SplOfferAvailable.text'){
ar[1]='true';
}else{
}
//make sure the selection is there!
groupedSelections[ar[0]] = groupedSelections[ar[0]] || [];
//at the value to the group.
groupedSelections[ar[0]].push(ar[1]);
});
return groupedSelections;
}
function prepareChecks(checkboxData) {
var groupedSelections = prepareGroups(checkboxData);
var checks = [];
//console.log(groupedSelections);
Object.keys(groupedSelections).forEach(function(group) {
//console.log("groupedSelections- "+groupedSelections);
//console.log("group- "+group);
var needToInclude = function(item) {
//console.log("item- "+item);
// use the angular parser to get the data for the comparson out.
var itemValue = $parse(group)(item);
var valueArr = groupedSelections[group];
//console.log("valueArr- "+valueArr);
function checkValue(value) { //helper function
return value == itemValue;
}
//check if one of the values is included.
return valueArr.some(checkValue);
};
checks.push(needToInclude); //store the function for later use
});
return checks;
}
return function(input, checkboxData, purgeCache) {
if (!purgeCache) { //can I return a previous 'run'?
// is the request the same as before, and is there an result already?
if (angular.equals(checkboxData, cache.checkboxData) && cache.result.length) {
return cache.result; //Done!
}
}
cache.checkboxData = angular.copy(checkboxData);
var result = []; // this holds the results
//prepare the checking functions just once.
var checks = prepareChecks(checkboxData);
input.every(function(item) {
if (checks.every(function(check) {
return check(item);
})) {
result.push(item);
}
return result.length < 10000000; //max out at 100 results!
});
cache.result = result; //store in chache
return result;
};
});
above code is for check box filter.
when i click on checkbox called "Availability" it does not filter the result.
Please help me out.
Thanks.
I think that the way you are navigating through json is wrong because if you put in this way it works
"Location": "Riyadh",
"AvlStatus": "AVAILABLE"
"Rooms": {.....
You have to go in some way through Rooms and right now I think you're not doing that

How to check if expression will have a value after evaluating

Let's say I have a following template:
"foo['x'] = '{{ myVar }}';"
Is there an angular way of checking if evaluating this against my current scope will give myVar some value ? I've got an array of such small templates and I only want to include them in the document when values are truthy. I was hoping either $interpolate, $parse or $eval might come in handy here. I know for sure that $interpolate is useless. What about the other two ? Maybe it's at least possible to get the name of the assigned value/expression ?
EDIT
I wasn't specific enough. What I was trying to achieve, was checking in advance if for example template '{{ myVar }}' evaluated against the current scope will return an empty string or value of the scope variable (if it exists). The case was really specific - when traversing an array of short templates I wanted to know if a template will return as an empty string or not, and only include it in my final html if it doesn't.
I'm not sure what are you trying to achieve, but to if you want to check if myVar is truthy in current scope, you can:
{{myVar ? "aw yiss" : "nope"}}
Evaluates to "aw yiss" if myVar is truthy and "nope" otherwise.
I ended up with a modified $interpolate provider but maybe someone knows a shorter solution :
app.provider('customInterpolateProvider', [
function $InterpolateProvider() {
var startSymbol = '{{';
var endSymbol = '}}';
this.startSymbol = function(value){
if (value) {
startSymbol = value;
return this;
} else {
return startSymbol;
}
};
this.endSymbol = function(value){
if (value) {
endSymbol = value;
return this;
} else {
return endSymbol;
}
};
this.$get = ['$parse', '$sce', function($parse, $sce) {
var startSymbolLength = startSymbol.length,
endSymbolLength = endSymbol.length;
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
allOrNothing = !!allOrNothing;
var startIndex,
endIndex,
index = 0,
expressions = [],
parseFns = [],
textLength = text.length,
exp;
var getValue = function (value) {
return trustedContext ?
$sce.getTrusted(trustedContext, value) :
$sce.valueOf(value);
};
var stringify = function (value) {
if (value == null) {
return '';
}
switch (typeof value) {
case 'string':
break;
case 'number':
value = '' + value;
break;
default:
value = angular.toJson(value);
}
return value;
};
var parseStringifyInterceptor = function(value) {
try {
return stringify(getValue(value));
} catch(err) {
console.err(err.toString());
}
};
while(index < textLength) {
if ( ((startIndex = text.indexOf(startSymbol, index)) !== -1) &&
((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) !== -1) ) {
exp = text.substring(startIndex + startSymbolLength, endIndex);
expressions.push(exp);
parseFns.push($parse(exp, parseStringifyInterceptor));
index = endIndex + endSymbolLength;
} else {
break;
}
}
if (!expressions.length && !text.contains(startSymbol) && !text.contains(endSymbol)) {
expressions.push(text);
}
if (!mustHaveExpression) {
var compute = function(values) {
for(var i = 0, ii = expressions.length; i < ii; i++) {
if (allOrNothing && angular.isUndefined(values[i])) {
return;
}
expressions[i] = values[i];
}
return expressions.join('');
};
return angular.extend(function interpolationFn(context) {
var i = 0;
var ii = expressions.length;
var values = new Array(ii);
try {
if (ii && !parseFns.length) {
return expressions[0];
} else {
for (; i < ii; i++) {
values[i] = parseFns[i](context);
}
return compute(values);
}
} catch(err) {
console.err(err.toString());
}
}, {
exp: text,
expressions: expressions,
$$watchDelegate: function (scope, listener, objectEquality) {
var lastValue;
return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
var currValue = compute(values);
if (angular.isFunction(listener)) {
listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
}
lastValue = currValue;
}, objectEquality);
}
});
}
}
return $interpolate;
}];
}
]);
Lines below were added because in some cases I have a predefined text in my short template and I always want to render it :
if (!expressions.length && !text.contains(startSymbol) && !text.contains(endSymbol)) {
expressions.push(text);
}
if (ii && !parseFns.length) {
return expressions[0];
} else {

Angular JS break ForEach

I have an angular foreach loop and i want to break from loop if i match a value. The following code does not work.
angular.forEach([0,1,2], function(count){
if(count == 1){
break;
}
});
How can i get this?
The angular.forEach loop can't break on a condition match.
My personal advice is to use a NATIVE FOR loop instead of angular.forEach.
The NATIVE FOR loop is around 90% faster then other for loops.
USE FOR loop IN ANGULAR:
var numbers = [0, 1, 2, 3, 4, 5];
for (var i = 0, len = numbers.length; i < len; i++) {
if (numbers[i] === 1) {
console.log('Loop is going to break.');
break;
}
console.log('Loop will continue.');
}
There's no way to do this. See https://github.com/angular/angular.js/issues/263. Depending on what you're doing you can use a boolean to just not going into the body of the loop. Something like:
var keepGoing = true;
angular.forEach([0,1,2], function(count){
if(keepGoing) {
if(count == 1){
keepGoing = false;
}
}
});
please use some or every instances of ForEach,
Array.prototype.some:
some is much the same as forEach but it break when the callback returns true
Array.prototype.every:
every is almost identical to some except it's expecting false to break the loop.
Example for some:
var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];
ary.some(function (value, index, _ary) {
console.log(index + ": " + value);
return value === "JavaScript";
});
Example for every:
var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];
ary.every(function(value, index, _ary) {
console.log(index + ": " + value);
return value.indexOf("Script") > -1;
});
Find more information
http://www.jsnoob.com/2013/11/26/how-to-break-the-foreach/
Use the Array Some Method
var exists = [0,1,2].some(function(count){
return count == 1
});
exists will return true, and you can use this as a variable in your function
if(exists){
console.log('this is true!')
}
Array Some Method - Javascript
As far as I know, Angular doesn't provide such a function. You may want to use underscore's find() function for this (it's basically a forEach which breaks out of the loop once the function returns true).
http://underscorejs.org/#find
If you use jQuery (hence not jqLite) in conjunction with AngularJS you can iterate with $.each - which allows breaking and continuing based on boolean return value expression.
JSFiddle:
http://jsfiddle.net/JEcD2/1/
Javascript:
var array = ['foo', 'bar', 'yay'];
$.each(array, function(index, element){
if (element === 'foo') {
return true; // continue
}
console.log(this);
if (element === 'bar') {
return false; // break
}
});
Note:
Though using jQuery is not bad, both native Array.some or Array.every functions are recommended by MDN as you can read at native forEach documentation:
"There is no way to stop or break a forEach loop. The solution is to use Array.every or Array.some"
Following examples are provided by MDN:
Array.some:
function isBigEnough(element, index, array){
return (element >= 10);
}
var passed = [2, 5, 8, 1, 4].some(isBigEnough);
// passed is false
passed = [12, 5, 8, 1, 4].some(isBigEnough);
// passed is true
Array.every:
function isBigEnough(element, index, array){
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true
Concretely, you can exit of a forEach loop, and of any place, throw an exception.
try {
angular.forEach([1,2,3], function(num) {
if (num === 2) throw Error();
});
} catch(e) {
// anything
}
However, it is better if you use other library or implement your own function, a find function in this case, so your code is most high-level.
Try this as break;
angular.forEach([0,1,2], function(count){
if(count == 1){
return true;
}
});
As the other answers state, Angular doesn't provide this functionality. jQuery does however, and if you have loaded jQuery as well as Angular, you can use
jQuery.each ( array, function ( index, value) {
if(condition) return false; // this will cause a break in the iteration
})
See http://api.jquery.com/jquery.each/
Normally there is no way to break an "each" loop in javascript.
What can be done usually is to use "short circuit" method.
array.forEach(function(item) {
// if the condition is not met, move on to the next round of iteration.
if (!condition) return;
// if the condition is met, do your logic here
console.log('do stuff.')
}
break isn't possible to achieve in angular forEach, we need to modify forEach to do that.
$scope.myuser = [{name: "Ravi"}, {name: "Bhushan"}, {name: "Thakur"}];
angular.forEach($scope.myuser, function(name){
if(name == "Bhushan") {
alert(name);
return forEach.break();
//break() is a function that returns an immutable object,e.g. an empty string
}
});
You can use this:
var count = 0;
var arr = [0,1,2];
for(var i in arr){
if(count == 1) break;
//console.log(arr[i]);
}
var ary = ["JavaScript", "Java", "CoffeeScript", "TypeScript"];
var keepGoing = true;
ary.forEach(function(value, index, _ary) {
console.log(index)
keepGoing = true;
ary.forEach(function(value, index, _ary) {
if(keepGoing){
if(index==2){
keepGoing=false;
}
else{
console.log(value)
}
}
});
});
$scope.arr = [0, 1, 2];
$scope.dict = {}
for ( var i=0; i < $scope.arr.length; i++ ) {
if ( $scope.arr[i] == 1 ) {
$scope.exists = 'yes, 1 exists';
break;
}
}
if ( $scope.exists ) {
angular.forEach ( $scope.arr, function ( value, index ) {
$scope.dict[index] = value;
});
}
I would prefer to do this by return. Put the looping part in private function and return when you want to break the loop.
I realise this is old, but an array filter may do what you need:
var arr = [0, 1, 2].filter(function (count) {
return count < 1;
});
You can then run arr.forEach and other array functions.
I realise that if you intend to cut down on loop operations altogether, this will probably not do what you want. For that you best use while.
This example works. Try it.
var array = [0,1,2];
for( var i = 0, ii = array.length; i < ii; i++){
if(i === 1){
break;
}
}
I would use return instead of break.
angular.forEach([0,1,2], function(count){
if(count == 1){
return;
}
});
Works like a charm.
Use Return to break the loop.
angular.forEach([0,1,2], function(count){
if(count == 1) {
return;
}
});
onSelectionChanged(event) {
let selectdata = event['api']['immutableService']['gridOptionsWrapper']['gridOptions']['rowData'];
let selected_flag = 0;
selectdata.forEach(data => {
if (data.selected == true) {
selected_flag = 1;
}
});
if (selected_flag == 1) {
this.showForms = true;
} else {
this.showForms = false;
}
}
Just add $index and do the following:
angular.forEach([0,1,2], function(count, $index) {
if($index !== 1) {
// do stuff
}
}

Resources