Ilya Chernomordik
Ilya Chernomordik

Reputation: 30195

How to use angular filter on multiple properties of the object

I have a simple ng-repeat like that:

<input type="text" ng-model="vm.filter">

<div ng-repeat="tenant in vm.tenants | filter : vm.filter : vm.contains">
 </div>

Now I want to filter tenants based on the value of the filter, e.g. to find if a name of a tenant contains the filter expression like that

function contains(actual, expected) {
            return actual.name.indexOf(expected) >= 0;
        }

What I do not understand is why I get a tenant.name in the contains function instead of the tenant itself. I know for a simple case I can do something like filter | {name: vm.filter} | vm.contains, but what if I want to do filtering based on multiple properties (e.g. name, phone, etc.)

Upvotes: 1

Views: 1407

Answers (3)

potatopeelings
potatopeelings

Reputation: 41065

What I do not understand is why I get a tenant.name in the contains function instead of the tenant itself.

What's happening is that angular is providing the comparator all levels of the object in an attempt to do a deep filtering i.e. it attempts to match your filter to all hierarchy levels in the object. If you console.log all the values, you'll see that you get the full object too (after all the properties).


One way to make this work would be something like

...
<div ng-repeat="tenant in vm.tenants | filter : vm.contains(vm.filter)">
...

and then

...
contains: function(filter) {
  return function(tenant) {
    return tenant.name.indexOf(filter) !== -1;
  }
}
...

Fiddle - https://jsfiddle.net/81384sd7/

Upvotes: 1

Adam Nierzad
Adam Nierzad

Reputation: 942

You can use an object to store the filters you want to apply. For example:

$scope.filterBy = {
  name: "Bob",
  phone: "07"
};

Then configure fields to edit the filters:

<input type="text" ng-model="filterBy.name" />
<input type="text" ng-model="filterBy.phone" />

Then just filter by this object.

<div ng-repeat="tenant in vm.tenants | filter : filterBy">

Take a look at my previous answer which is very similar except also allows selections to be made before a filter being applied manually with a button:

Applying a angularjs filter after "Apply" button click

I hope this helps.

Upvotes: 1

Brett DeWoody
Brett DeWoody

Reputation: 62743

You'll want to test for the presence of both those conditions and return the value if both are present. Something like this:

function contains(actual, expected) {
  if (actual.name.indexOf(expected) >= 0 && actual.phone.indexOf(expected) >= 0) {
    return actual;
  }
}

Upvotes: 0

Related Questions