AngularJS multiselect custom filter not working as intended - arrays

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 [];
};
}

Related

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.

Infdig in Custom groupBy

i recently needed some kinda customized repeater, which group data by their key, but not simply group them all together, so i read several references and things,... and at last i come up to copy
groupBy from this article which he seem to complete it at best, ...
http://sobrepere.com/blog/2014/10/14/creating-groupby-filter-angularjs/
And then i customized so it become like this:
the things my group by do... is:
Group Data Together Until It Reach Differences.
but the matter is that though it work, it still generate infdig, i know it's because the digest done call other one, but what i don't know is how to solve it in very easy and understandable manner, as i'm new to JavaScript...
app.filter('groupBy', function () {
var results = {};
return function (data, key) { //Data => My Objects Array - Key => Name Of Filtered Property
if (!(data && key)) return;
var result;
if (!this.$id) {
result = {};
} else {
var scopeId = this.$id;
if (!results[scopeId]) {
results[scopeId] = {};
this.$on("$destroy", function () {
delete results[scopeId];
});
}
result = results[scopeId];
}
for (var groupKey in result)
result[groupKey].splice(0, result[groupKey].length);
var grpKey = -1; //GroupKey
var lastUserId;
for (var i = 0; i < data.length; i++) {
if (!result[grpKey] || lastUserId && lastUserId != data[i][key]) // Ex.: result[data[0]["UserId"]]{ => return UserId
result[++ grpKey] = [];
result[grpKey].push(data[i]);
lastUserId = data[i][key];
}
var keys = Object.keys(result);
for (var k = 0; k < keys.length; k++) {
if (result[keys[k]].length === 0)
delete result[keys[k]];
}
return result;
};
});
In this url is working perfectly...
http://plnkr.co/edit/8jB4wSRtKfVmEsTGZtfV?p=preview
app.filter('groupBy', function ($timeout) {
return function (data, key) {
if (!key) return data;
var outputPropertyName = '__groupBy__' + key;
if(!data[outputPropertyName]){
var result = {};
for (var i=0;i<data.length;i++) {
if (!result[data[i][key]])
result[data[i][key]]=[];
result[data[i][key]].push(data[i]);
}
Object.defineProperty(result, 'length', {enumerable: false, value: Object.keys(result).length});
Object.defineProperty(data, outputPropertyName, {enumerable:false, configurable:true, writable: false, value:result});
$timeout(function(){delete data[outputPropertyName];},0,false);
}
return data[outputPropertyName];
};
});

How to push a JSON object to an array in AngularJS

I need to push a JSON object to AngularJS and need to check before if the value for one of the objects exist. I need to overwrite the data.
$scope.setData = function(survey, choice) {
keepAllData.push({
'surveyId': survey.id,
'choiceId': choice.id
});
console.log(keepAllData);
toArray(keepAllData);
alert(JSON.stringify(toArray(keepAllData)));
$scope.keepAllDatas.push({
'surveyId': survey.id,
'choiceId': choice.id
});
var items = ($filter('filter')(keepAllDatas, {
surveyId: survey.id
}));
}
function toArray(obj) {
var result = [];
for (var prop in obj) {
var value = obj[prop];
console.log(prop);
if (typeof value === 'object') {
result.push(toArray(value));
console.log(result);
} else {
result.push(value);
console.log(result);
}
}
return result;
}
If the survey id exists in keepalldata, I need to change the recent value with choiceid. Is it possible to do with AngularJS?
Try with this: Before pushing data you have to check if the survey id exists or not. If it exists you have to update choice with the corresponding survey id, otherwise you can push directly.
$scope.setData = function(survey, choice) {
var item = $filter('filter')(keepAllData, {
surveyId: survey.id
});
if (!item.length) {
keepAllData.push({
'surveyId': survey.id,
'choiceId': choice.id
});
} else {
item[0].choiceId = choice.id;
}
console.log(keepAllData);
}
Demo
$scope.keepAllDatas = [];
$scope.setData = function(survey, choice) {
if($scope.keepAllDatas.length == 0) {
$scope.keepAllDatas.push({'surveyId':survey.id,'choiceId':choice.id});
}
else {
var items = ($filter('filter')( $scope.keepAllDatas, {surveyId: survey.id }));
for (var i = items.length - 1; i >= 0; i--) {
// alert(items[i].surveyId);
if(items[i].surveyId == survey.id) {
console.log($scope.keepAllDatas.indexOf(survey.id));
$scope.keepAllDatas.splice($scope.keepAllDatas.indexOf(survey.id),1);
console.log("Removed data")
}
}
$scope.keepAllDatas.push({'surveyId':survey.id, 'choiceId':choice.id});
console.log( $scope.keepAllDatas)
// alert(items[0].surveyId);
}
}

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 {

Resources