92

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.

Tushar
  • 85,780
  • 21
  • 159
  • 179
user2368436
  • 933
  • 1
  • 6
  • 4
  • 3
    Why do you need a filter? Usually filters are used from templates. Can you not just have a plain function in your controller if your are only using it from there? – Ketan May 10 '13 at 03:44
  • instead of manually going thro each element of the array, i thought we could use the $filter('filter') functionality of angular (which will take care of iterating thro each element if we just specify the predicate function) – user2368436 May 15 '13 at 16:01

3 Answers3

178

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;
  };
};
Cheeso
  • 189,189
  • 101
  • 473
  • 713
Tosh
  • 35,955
  • 11
  • 65
  • 55
  • I will not be using this criteriaMatch function from the html.. how will I call it from inside the controller is this correct ? $filter('filter')(array, function(){ return criteriaMatch(item, criteria); }); – user2368436 May 15 '13 at 15:50
  • 6
    If you are not using it in your template, defining filter does not give you any advantage. You can simply define a simple javascript function, as it is even shorter there. You can use native `filter` method in Array object: `array.filter(function(item){return item.name === criteria.name;})` – Tosh May 15 '13 at 22:59
  • I do have a javascript function. just wanted to make sure that angular did not have an easier way of doing it.. i will accept your answer. thx. – user2368436 May 16 '13 at 13:51
2

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.

Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
-1

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)');
cafesanu
  • 435
  • 1
  • 4
  • 12