AngularJS custom filter function - arrays

Inside my controller, I would like to filter an array of objects. Each of these objects is a map which can contain strings as well as lists
I tried using $filter('filter')(array, function) format but I do not know how to access the individual elements of the array inside my function. Here is a snippet to show what I want.
$filter('filter')(array, function() {
return criteriaMatch(item, criteria);
});
And then in the criteriaMatch(), I will check if each of the individual property matches
var criteriaMatch = function(item, criteria) {
// go thro each individual property in the item and criteria
// and check if they are equal
}
I have to do all these in the controller and compile a list of lists and set them in the scope. So I do need to access the $filter('filter') this way only. All the examples I found in the net so far have static criteria searches inside the function, they don't pass an criteria object and test against each item in the array.

You can use it like this:
http://plnkr.co/edit/vtNjEgmpItqxX5fdwtPi?p=preview
Like you found, filter accepts predicate function which accepts item
by item from the array.
So, you just have to create an predicate function based on the given criteria.
In this example, criteriaMatch is a function which returns a predicate
function which matches the given criteria.
template:
<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
{{ item }}
</div>
scope:
$scope.criteriaMatch = function( criteria ) {
return function( item ) {
return item.name === criteria.name;
};
};

Here's an example of how you'd use filter within your AngularJS JavaScript (rather than in an HTML element).
In this example, we have an array of Country records, each containing a name and a 3-character ISO code.
We want to write a function which will search through this list for a record which matches a specific 3-character code.
Here's how we'd do it without using filter:
$scope.FindCountryByCode = function (CountryCode) {
// Search through an array of Country records for one containing a particular 3-character country-code.
// Returns either a record, or NULL, if the country couldn't be found.
for (var i = 0; i < $scope.CountryList.length; i++) {
if ($scope.CountryList[i].IsoAlpha3 == CountryCode) {
return $scope.CountryList[i];
};
};
return null;
};
Yup, nothing wrong with that.
But here's how the same function would look, using filter:
$scope.FindCountryByCode = function (CountryCode) {
// Search through an array of Country records for one containing a particular 3-character country-code.
// Returns either a record, or NULL, if the country couldn't be found.
var matches = $scope.CountryList.filter(function (el) { return el.IsoAlpha3 == CountryCode; })
// If 'filter' didn't find any matching records, its result will be an array of 0 records.
if (matches.length == 0)
return null;
// Otherwise, it should've found just one matching record
return matches[0];
};
Much neater.
Remember that filter returns an array as a result (a list of matching records), so in this example, we'll either want to return 1 record, or NULL.
Hope this helps.

Additionally, if you want to use the filter in your controller the same way you do it here:
<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
{{ item }}
</div>
You could do something like:
var filteredItems = $scope.$eval('items | filter:filter:criteriaMatch(criteria)');

Related

How can do array map inside methods in vuejs

How can ı equalize my array ıd and my value ıd and access value.name I didn't do it
This is my code:
activity(val) {
var act = this.items.map(function (val) {
if (element.ActivityID== val) {
return element.ActivityName
}
return act
});
Perhaps this?
activity (val) {
const activity = this.items.find(item => item.ActivityID === val)
return activity && activity.ActivityName
}
This just finds the item with the corresponding ActivityID and then returns its ActivityName.
Your original code contained several possible mistakes:
Two different things called val.
element doesn't appear to be defined.
The return act was inside the map callback. The activity method itself wasn't returning anything.
Not really clear why you were using map to find a single item. map is used to create a new array with the same length as the original array with each item in the new array determined by the equivalent item in the original array. It 'maps' the items of the input array to the items in the output array.

Conditional filter for checking all keys in array of objects using multiple inputs

I have an array of objects:
scope.values = [
{'key1':'valueA', 'key2': 'valueD'},
{'key1':'valueB'},
{'key1':'valueC'}
]
And I would like to filter a search input, which can contain multiple words separated by either comma or space:
<input ng-model="scope.search"></input>
We can list the array as follows:
<p ng-repeat="index, obj in scope.values | filter:scope.search"></p>
However, this only works for one input. What can I do when I have multiple inputs e.g. John Doe.
Note that I want it to be conditional. So not if John or Doe is found, but when John and Doe are found.
I don't think the built-in filter can do that. What you probably want is a custom filter, as described in the documentation here (about half way down the page) and in the official tutorial here.
For example, this custom filter should do what you want.
app.filter("multiSearch", [
function() {
//"data" is your searchable array, and "search" is the user's search string.
return function(data, search) {
//Get an array of search values by splitting the string on commas and spaces.
var searchArray = search.toLowerCase().split(/[, ]/);
//Use javascript's native Array.filter to decide which elements to cut and to keep.
return data.filter(function(item) {
//If the item contains ALL of the search words, keep it.
var foundCount = 0;
for (var searchElement of searchArray) {
for (var attribute in item) {
if (
String(item[attribute])
.toLowerCase()
.includes(searchElement)
) {
foundCount++;
break;
}
}
}
if (foundCount === searchArray.length) {
//Matched all search terms. Keep it.
return true;
}
else {
//Not a match. Cut it from the result.
return false;
}
});
};
}
]);
Then in your html you can call it like so:
<p ng-repeat="index, obj in scope.values | multiSearch:scope.search"></p>
Another thing you might consider, as suggested in the comments, is to forego using filters altogether and just run the logic inside your controller. You can use a lot of the logic provided in the example filter above -- you just have to implement your own system to run the filtering logic when the search query changes. There are benefits in avoiding filters in angularjs, but that is another topic.

order by of angularjs for sorting based on three different parameters

I am using order by of Angular for sorting but I want to sort data based on three different fields, i.e success, in-progress and failed, without using any constant and variable directly from in-built function. Is there any way?
If you want you can call a function to sort your data as you want.
you can call following custom 'orderBy'
$scope.sort = function(column,reverse) {
$scope.persons = $filter('orderBy')($scope.persons,column,reverse);
};
'$scope.persons' - is your collection of data you need to order
'column' - name of the column you want to sort data
'reverse'- bool value to reverse the order
and you can call this 'sort' function from your View(HTML) as below.
data-ng-click="sort('name',nameReverse)"
you can pass array of fields to orderBy
<div ng-repeat="row in list | orderBy:['param1','param2']">
....
</div>
EDIT
to do it in javascript
$scope.sortedList = $filter('orderBy')(list,['param1', 'param2']);
EDIT
in smart table
function customSortAlgorithm(arrayRef, sortPredicate, reverse) {
//do some stuff
return sortedArray;
}
scope.globalConfig = {
sortAlgorithm: customSortAlgorithm
};

Angularjs get length of returned filter in ng-repeat

I'm using ng-repeat to create a list of entires and using a filter.
Is it possible to get the number of entries returned, like a length
data-ng-repeat="entry in entries | filter: { country_code : countryCode }"
It is little bit tricky, use ng-init:
ng-init="filter_len = (entries | filter: { country_code : countryCode }).length"
Example: http://jsfiddle.net/KJ3Nx/
As you know filter responsible to "filter" the input list and it returns filtered list where objects have the same structure. Otherwise you get digest cycle reentering that causes Exceptions (aka > 10 cycles).
1st way
Get length after filtering:
<pre>{{(entries| myfilter:types).length }}</pre>
See Example
2nd way
Use custom filter and get length from there.
iApp.filter('myfilter', function() {
return function( entries) {
var filtered = [];
angular.forEach(entries, function(entry) {
filtered.push(entry);
});
// here fetch list length
return filtered;
};
});
I suppose the following code will work for you:
<p>Filtered number: {{(entries|filter:{country_code:countryCode}).length}}</p>
<p>Total number: {{entries.length}}</p>

AngularJS: How to write a two-level sorting function

My goal is to write an AngularJS ordering function, which behaves similarily, for example, to MySQL's "ORDER BY column1, column2". Means: if "column1" is same, sort by "column2".
The solution for only one criterium is, as known:
$scope.myOrderFn = function (item) {
return item.column1;
}
How to add the second criterium?
It seems to be that the sort function is more a "order by key extract function".
Therefore you cannot just concat string values because this would break the sorting.
However, you can pass more than one sort function as you would with column names. It's not in the offical documentation but the source is straightforward.
I think your only option is to pass two sort functions as you would with the sort columns:
Template
<div ng-repeat="item in items | orderBy:['column1','column2']">
{{item.column1}}-{{item.column2}}
</div>
<div ng-repeat="item in items | orderBy:[sort1,sort2]">
{{item.column1}}-{{item.column2}}
</div>
Controller
$scope.sort1 = function (item) {
return item.column1;
}
$scope.sort2 = function (item) {
return item.column2;
}

Resources