5

This seems like it must be simple, I just cannot find the answer.

Let's say I have an array of data, set out like the following:

friends = [{name:'John', age:60, location:'Brighton', street:'Middle Street'},
{name:'Bob', age:5, location:'Brighton', street:'High Street'}];

Now, I want to filter the data based on a text input like so:

<input ng-model="searchText">
<ul>
    <li ng-repeat="friend in friends | orderBy:'name' | filter:searchText">
    {{friend.name}} - {{friend.location}}</li>
</ul>

This works fine but it filters the input text based on every attribute of the friend object (name, age, location and street). I'd like to be able to filter based on name and location only (ignoring age and street). Is this possible without a custom filter?

4 Answers 4

7

Yes, it's possible by simply passing a predicate to the filter instead of a string:

<li ng-repeat="friend in friends | orderBy:'name' | filter:friendContainsSearchText">

$scope.friendContainsSearchText = function(friend) {
    return friend.name.indexOf($scope.searchText) >= 0 || friend.location.indexOf($scope.searchText) >= 0
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, works nicely. Only thing worth mentioning is that I needed to convert the text to lowercase and add if(!$scope.searchText) return 1; to get it to work.
Just to note- adding 'if(!$scope.searchText) return 1;' will cause it to return all results (no filtering) if no search text is entered. This is an upside of this approach over the approach I list if you need that.
2

Here is how we do it with a custom filter.

DEMO: http://plnkr.co/edit/q7tYjOvFjQHSR0QyGETj?p=preview)

[array] | search:query:columns:operator

> query: this is the term you are looking for
> columns: an array of the names of the properties you want to look for (if empty, will use the angular filter with query)
> operator: a boolean to switch between OR (true) and AND (false, default)

html

<ul>
  <li ng-repeat="item in list | search:query:['name','location']:operator">
    <pre>{{item | json}}</pre>
  </li>
</ul>

js

app.filter('search', function($filter) {
  return function(input, term, fields, operator) {
    if (!term) {
       return input;
    }

    fields || (fields = []);

    if (!fields.length) {
      return $filter('filter')(input, term);
    }

    operator || (operator = false); // true=OR, false=AND

    var filtered = [], valid;

    angular.forEach(input, function(value, key) {
      valid = !operator;
      for(var i in fields) {
        var index = value[fields[i]].toLowerCase().indexOf(term.toLowerCase());
        // OR : found any? valid
        if (operator && index >= 0) { 
          valid = true; break;
        } 
        // AND: not found once? invalid 
        else if (!operator && index < 0) { 
          valid = false; break;
        }
      }
      if (valid) {
        this.push(value);
      }
    }, filtered);

    return filtered;
  };
});

Comments

1

Alternatively you can use:

<li ng-repeat="friend in friends | orderBy:'name' | filter:{ name :searchText}">

3 Comments

This is probably what you want, except searchText needs quotes around it. filter:{ name: 'searchText' } . This will tell angular that it is a string and not an expression.
Actually @Adam check out this fiddle: jsfiddle.net/Dwesk/1 It doesn't work with quotes, does without.
You're absolutely right, we wanted an expression in this case, I misunderstood the initial question and answer.
-1

You can put several filters just like ....

<div>
    <input ng-model="Ctrl.firstName" />
    <input ng-model="Ctrl.age" />

    <li ng-repeat = "employee in Ctrl.employees | filter:{name:Ctrl.firstName} | filter:{age:Ctrl.age}">{{employee.firstName}}</li>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.