AngularJs - Filter an object only by certain fields in a custom filter - angularjs

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)

Related

How to filter the objects with multiple values?

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

angularjs filter nested array-using-checkboxes-with-angularjs

I am following this approach to filter nested json response. I have a nested property like this:
instances:{
instance:[
{cname:'name1', location:'pa', price:40, model:'2014' },
{cname:'name1', location:'ga', price:30 , model:'2014'},
{cname:'name1', location:'ga', price:20, model:'2010' }
]}
I can filter by top level properties using the above mentioned example but not the child properties.
I have modified above example to show nested properties of my json here.http://jsfiddle.net/jackAndy/qygL2m01/4/. I am new to angularjs.
First of all - why You use instances.instance? It it not principally, use players.instances = [];
Use Group functions only 1 time after data loading; Watching filters - it's not necessary in this case;
Function for get filters values (I use underscore uniq function, You can use Your own algorithm for this):
$scope.getFieldsValues = function(field){
var result = [];
for(var i = 0; i < $scope.players.length; i++){
result.push($scope.players[i][field]);
}
return _.uniq(result);
};
Filter for players:
$scope.testFl = function(el){
for(var filter in $scope.filters){
var filterArray = [];
for(var i in $scope.filters[filter]){
if($scope.filters[filter][i]) filterArray.push(i);
}
//You can make array with instances properties & compare with it;
if(filter === 'location'){
if(el.instances && el.instances.length > 0){
var intersection = el.instances.filter(function(n) {
return filterArray.indexOf(n[filter]) != -1
});
} else if(filterArray.length > 0){return false;}
} else {
if(filterArray.length > 0 && filterArray.indexOf(el[filter]) === -1) return false;
}
}
return true;
};
Template:
<li ng-repeat="player in players | filter:testFl" >
Filter for instances:
$scope.testFl2 = function(el){
var filterArray = [];
for(var i in $scope.filters.location){
if($scope.filters.location[i]) filterArray.push(i);
}
return filterArray.length > 0 && filterArray.indexOf(el.location) === -1 ? false : true;
};
Template:
<span ng-repeat="loc in player.instances | filter:testFl2" >
Fiddle for this;
UPDATE:
Function for count:
$scope.getCount = function(field, value){
var obj = {};
obj[field] = value;
return _.where($scope.players, obj).length;
};
Update fiddle - update underscore, add count function;
I hope this will help you;
For answer were used:
Add underscore to jsfiddle;
variable property name in where underscore.js;

AngularJS, Add Rows

Morning,
We are trying to implement this add row Plunkr, it seems to work however our input data seems to repeat. Does anyone know of a solution to add a unique id to preview duplicated fields ?
Here is our current Plunkr and LIVE example.
$scope.addRow = function(){
var row = {};
$scope.productdata.push(row);
};
$scope.removeRow = function(index){
$scope.productdata.splice(index, 1);
};
$scope.formData you have is not an array, but just one object. All your rows are bound to that object and hence all of them reference the same data.
The reason you get a new row added is because your ng-repeat is bound to $scope.productData and you add extra record in it. You should bind your form elements to the properties in the row object that you create
a simple example is :
In your template
<div ng-repeat="product in products">
<input type="text" ng-model="product.title">
</div>
In your controller
$scope.addProduct = function(){
var product = {};
$scope.productData.add(product);
}
You'd then always only work with the productData array and bind your model to them.
Even in your backend calls, you'd use productData instead of your formData.
Hope this helps.
U can use a filter : This will return Unique rows only
app.filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
I think the reason why this is happening is that the addRow() function is just pushing an empty son object into the $scope.productdata array, whereas all input fields are bound to $scope.formData[product.WarrantyTestDescription]. I think you mean to bind the input fields to the properties of the product object.

Angular filter returning an array of objects causing infinite $digest loop

I have a custom filter which returns an array of matches to search field input and it works, but only after causing an infinite $digest loop. This also apparently only began happening after upgrading from Angular 1.0.6. This is the filter code:
angular.module("Directory.searches.filters", [])
.filter('highlightMatches', function() {
var ary = [];
return function (obj, matcher) {
if (matcher && matcher.length) {
var regex = new RegExp("(\\w*" + matcher + "\\w*)", 'ig');
ary.length = 0;
angular.forEach(obj, function (object) {
if (object.text.match(regex)) {
ary.push(angular.copy(object));
ary[ary.length-1].text = object.text.replace(regex, "<em>$1</em>");
}
});
return ary;
} else {
return obj;
}
}
});
I've seen elsewhere that this could be caused by having the filter inside of an ng-show, or that it's because the array being returned is interpreted as a new array every time it's checked, but I'm not sure how I could fix either problem. You can see a production example of this issue at https://www.popuparchive.com/collections/514/items/4859 and the open source project is available at https://github.com/PRX/pop-up-archive. Thank you!
This is happening because of angular.copy(object). Each time the digest cycle runs, the filter returns an array of new objects that angular has never seen before, so the the digest loop goes on forever.
One solution is return an array containing the original items that match the filter, with a highlightedText property added to each item...
angular.module("Directory.searches.filters", [])
.filter('highlightMatches', function() {
return function (items, matcher) {
if (matcher && matcher.length) {
var filteredItems = [];
var regex = new RegExp("(\\w*" + matcher + "\\w*)", 'ig');
angular.forEach(items, function (item) {
if (item.text.match(regex)) {
item.highlightedText = item.text.replace(regex, "<em>$1</em>");
filteredItems.push(item);
}
});
return filteredItems;
} else {
angular.forEach(items, function (item) {
item.highlightedText = item.text;
});
return items;
}
}
});
You can bind to the highlightedText property, something like...
<div>
Results
<ul>
<li ng-repeat="item in items | highlightMatches : matcher" ng-bind-html="item.highlightedText"></li>
</ul>
</div>

angularjs - ngRepeat with OR filter

I have a list with the items (name: String, age: Int, checked:Boolean).
This list is displayed with an ng-repeat.
I want to enable the user to search the list using a searchfield, but the search must not affect the checked-values.
the search should only trigger, if the users enters something in the searchfield
if the seachfield is filled, the search should filter as usual, but the checked items must not be filtered out.
I tried to create a custom filter. I have problems in understanding the $filter('filter') function with my OR-logic.
Could anyone help me untie the knot in my brain?
app.filter('mySearchFilter', function($filter) {
return function(data, searchText) {
if(!searchText || searchText.length === 0) {
return data;
}
console.log(searchText);
return $filter('filter')(data, searchText);
//how can I provide additional, OR-concatinated, filter-criteria?
}
});
Check out my plunk for the minimal-example-code.
http://plnkr.co/edit/3xHLOrSPD3XZy2K9U2Og?p=preview
As I understand you, you are looking for a union function. Underscore provide such a function. With this you may write your filter in this way:
app.filter('mySearchFilter', function($filter) {
return function(data, searchText) {
if(!searchText || searchText.length === 0) {
return data;
}
var allChecked = data.filter(function(d){return d.checked});
var allMatched = $filter('filter')(data, searchText);
return _.union(allMatched, allChecked);
}
});
have a look at: http://documentcloud.github.io/underscore/#union and don't forget to include the script:
<script src="http://documentcloud.github.io/underscore/underscore.js"></script>
PLUNKR

Resources