I have a teamDetails array, within which is a squad array, within which are player objects. Each player object has an injured property which contains the value "true" or "false".
I want to write a function that loops through the array returning only players whose injured property evaluates to true.
This is what I have so far (not working):
$scope.injuredPlayerSearch = function() {
var injuredPlayers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o[injured] === true) {
injuredPlayers.push(o)
}
});
return injuredPlayers;
}
I can't see what's wrong with this. If anyone can, would appreciate some help.
You do not need to write any function. angular is there for you.
var injuredPlayers = $filter('filter')($scope.teamDetails.squad, {injured:true}, true);
Here $filter is angular filter. Do dependency inject to your controler or sevice where you are using.
For more about angular filter refer here
Note: 2nd true is for strict type checking. it is equivalent to injured===true
EDIT
For showing it to directly on view angular has much better solution.
{{teamDetails.squad | filter:{injured:true}:true}}
For use in view no need any dependency injection or controller.
If the iteration is within an array of array this is the correct implementation:
$scope.injuredPlayerSearch = function() {
var injuredPlayers = [];
$scope.teamDetails.forEach(function(t){
t.squad.forEach(function(o) {
if (o[injured] === true) {
injuredPlayers.push(o)
}
});
});
return injuredPlayers;
}
You could use filter to return players who are injured:
$scope.injuredPlayerSearch = function() {
return $scope.teamDetails.squad.filter(function(o) {
return o[injured];
});
}
try this
var injuredPlayers = [];
angular.forEach($scope.teamDetails.squad,function(s){
if (s.injured === true) {
injuredPlayers.push(s)
}
})
return injuredPlayers;
Use the javascript filter
var players = [{ id : 0 , injured : true},
{ id : 1 , injured : false},
{ id : 2 , injured : false},
{ id : 3 , injured : true},
{ id : 4 , injured : true}];
var injuredPlayers = players.filter(filterByInjured)
function filterByInjured(player) {
if ('injured' in player && typeof(player.injured) === 'boolean' && player.injured === true) {
return true;
}
}
console.log(injuredPlayers);
You did everything correct just left something
$scope.injuredPlayerSearch = function() {
var injuredPlayers = [];
angular.forEach($scope.teamDetails.squad,function(o) {
if (o[injured] === true) {
injuredPlayers.push(o)
}
});
return injuredPlayers;
}
Related
I wrote a little program in angular using ui-select. And I want to write a filter that do an OR search in different fields (that can be nested fields in a json). In the github of ui-select I found this filter that can do a similar things (but only with simple fields) :
/**
* AngularJS default filter with the following expression:
* "person in people | filter: {name: $select.search, age: $select.search}"
* performs an AND between 'name: $select.search' and 'age: $select.search'.
* We want to perform an OR.
*/
app.filter('propsFilter', function() {
return function(items, props) {
var out = [];
if (angular.isArray(items)) {
var keys = Object.keys(props);
items.forEach(function(item) {
var itemMatches = false;
for (var i = 0; i < keys.length; i++) {
var prop = keys[i];
var text = props[prop].toLowerCase();
if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
itemMatches = true;
break;
}
}
if (itemMatches) {
out.push(item);
}
});
} else {
// Let the output be the input untouched
out = items;
}
return out;
};
});
My json object where I want to apply this filter has this structure :
$scope.contracts = [{
name: "contract1.00",
value: 10,
id :{
id : 8000,
code : 2
},
policy : {
info : {
name : "test1",
country : "test"
}
}
}
//other elements....
The problem is that this 'propsFilter' only works with simple fields. So, if I write this :
propsFilter: {name: $select.search, value : $select.search}
It will work correcly and do an OR search in these two fields (name OR values). But in my example, I want to do the OR search with two others fields : id.id and policy.info.name.
So, what I want to do is to use a line like this :
propsFilter: {name: $select.search, value : $select.search, id.id : $select.search, policy.info.name : $select.search }
Finally, here is my plunker : http://plnkr.co/edit/ej2r7XqeTPOC5d1NDXJn?p=preview
How can I do that in the same search filter??
I've updated your plunker. First of all, break from the loop caused the filter to work only on first property name, I've also added a condition in the if item[prop] && so your code doesn't throw an error when the property does not exist on the item
http://plnkr.co/edit/CwNANzodvjnuMCNyJYtA?p=preview
app.filter('propsFilter', function($parse) {
return function(items, props) {
var out = [];
if (angular.isArray(items)) {
var keys = Object.keys(props);
items.forEach(function(item) {
var itemMatches = false;
for (var i = 0; i < keys.length; i++) {
var prop = $parse(keys[i])(item);
var text = props[keys[i]].toLowerCase();
if (prop && prop.toString().toLowerCase().indexOf(text) !== -1) {
itemMatches = true;
}
}
if (itemMatches) {
out.push(item);
}
});
} else {
// Let the output be the input untouched
out = items;
}
return out;
};
});
I am very new to angular and, I am not sure how to control the behavior of my filters.
In the app, I have two different single-select drop down controls that filter the results of my data set and fill a table. However, even though these filters work, the results are dependent of both controls and if both are not being used , the empty set is returned. So, my question is: How can I use these filters optionally? So, the app returns every result when the filters are not used or returns the filtered results by one of the controls or both?
Thank you
Here is the code:
AngularJS
The filters for each control. They look very similar:
.filter('byField', function () {
return function (results, options) {
var items = { options: options, out: [] };
angular.forEach(results, function (value, key) {
for (var i in this.options) {
if ((options[i].value === value.fieldId &&
options[i].name === "Field" &&
options[i].ticked === true)) {
this.out.push(value);
}
}
}, items);
return items.out;
};
})
.filter('byClass', function () {
return function (results, options) {
var items = { options: options, out: [] };
angular.forEach(results, function (value, key) {
for (var i in this.options) {
if ((options[i].value === value.documentClass &&
options[i].name === "Class" &&
options[i].ticked === true)) {
this.out.push(value);
}
}
}, items);
return items.out;
};
})
HTML
This is what I am doing to populate the rows of the table:
<tr ng-repeat="result in results | byField:outputFields | byClass:outputClasses">
<td>{{result.documentId}}</td>
...
</tr>
Dorado7.1 in all event listeners provides a view implicit variable pointing to the current event host's view, the variable can completely replace the use of this scenario.
Well, as I imagined the answer was more related to set theory than to angular.
I just made an union between the empty set and every result, and it worked.
.filter('byField', function () {
return function (results, options) {
var items = { options: options, out: [] };
angular.forEach(results, function (value, key) {
if (options.length) {
for (var i in this.options) {
if ((options[i].value === value.fieldId &&
options[i].name === "Field" &&
options[i].ticked === true)) {
this.out.push(value);
}
}
} else {
this.out = results.slice();
}
}, items);
return items.out;
};
})
I have the array of objects. when I require to filter the object by single vaue i am doing like this:
$scope.filteredByPhase = $filter('filter')($scope.allApps, {Phase:"All"});
$scope.allAppsBatch = $scope.filteredByPhase;
But as a option, I would like to filter the objects by 2 'Phase` values by "All" or "Home" in this case how to filter?
I tried like this:
$scope.filteredByPhase = $filter('filter')($scope.allApps, {Phase:("All" || "Home")});
$scope.allAppsBatch = $scope.filteredByPhase;
But not works.. any one guide me please?
In AngularJS, you can use a function as an expression in the filter. In the function you can validate the condition and return Boolean value. All the falsy items are filtered out of the result. So you can do
$scope.filteredByPhase = $filter('filter')($scope.allApps, function (app) {
if (app.Phase == "All" || app.Phase == "Home") {
return true;
}
return false;
});
Read More : AngularJS Filter Documentation
Use $filter passing an anonymous comparison function.
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
return (item.Phase == "all") ? true : false;
});
Keep in mind that you may use Array.filter as well:
$scope.items = [{
Phase: "home"
}, {
Phase: "all"
}, {
Phase: "all"
}, {
Phase: "home"
}];
console.log($scope.items);
$scope.filteredItems = $scope.items.filter(function (item) {
return (item.Phase == "all") ? true : false;
})
console.log($scope.filteredItems)
You may also trigger multiple filtering actions using chaining:
$scope.fi = $scope.i.filter(func1).filter(func2);
I'm working on this codepen. The data comes from an array of objects, and I need to make a filter only by name and amount.
I have this code, but if you type a character in the search box, it only search by amount, and not by name too. In other words, if the you type 'warren' or '37.47' it has to return the same result, but doesn't works.
var filterFilter = $filter('filter');
$scope.filter = {
condition: ""
};
$scope.$watch('filter.condition',function(condition){
$scope.filteredlist = filterFilter($scope.expenses,{name:condition} && {amount:condition});
$scope.setPage();
});
You want to create a custom filter for your app.
directiveApp.filter("myFilter", function () {
return function (input, searchText) {
var filteredList = [];
angular.forEach(input, function (val) {
// Match exact name
if (val.name == searchText) {
filteredList.push(val);
}
// Match exact amount
else if (val.amount == searchText) {
filteredList.push(val);
}
});
input = filteredList;
return input;
};
});
You can write your logic in this filter and now use this filter to filter your list.
Update
You can just implement this filter to your custom filter pagination.
Here is the new version of your code. Codepen
List of updates on your code
Added new filter parameter to your ng-repeat attribute
ng-repeat="expense in filteredlist | pagination: pagination.currentPage : numPerPage : filter.condition"
...
Well, finally (based in the idea of Abhilash P A and reading the docs), I solved my question in this way:
var filterFilter = $filter('filter');
$scope.filter = {
condition: ""
};
$scope.$watch('filter.condition',function(condition){
$scope.filteredlist = filterFilter($scope.expenses,function(value, index, array){
if (value.name.toLowerCase().indexOf(condition.toLowerCase()) >= 0 ) {
return array;
}
else if (value.amount.indexOf(condition) >= 0 ) {
return array;
}
});
$scope.setPage();
});
The final codepen ! (awsome)
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