Question

I've got a text box in my html and I would like to filter the results on my page by a logical AND of the terms I type in the box. Let me demonstrate

Suppose on my page I've got

- Example number 1
- Example number 2
- Example number 3

Normally, if I want to filter the results I'll do something like

<input type= "text" ng-model= "query">

And later

<tr ng-repeat= "thing in blah | filter : query">
    <td> {{thing}} </td>
</tr>

So if I typed in

"Example"

I would understandably not "filter" anything. However, how would I do a logical AND, with multiple search terms? For example, if I type in

"Example 1"

I should get back only the first example, because it contains both "Example" AND "1". I've not seen anything in the angular documentation that would allow me to do this, but I'm sure it can be done by creating my own filter, I just don't have any experience in doing something like this.

Was it helpful?

Solution

Create a custom filter:

filter('and', function($log) {
  return function(items, query) {
    if (!query) return items; // return all items if nothing in query box

    var terms = query.split(' '); //split query terms by space character
    var arrayToReturn = [];

    items.forEach(function(item){ // iterate through array of items
      var passTest = true;
      terms.forEach(function(term){ // iterate through terms found in query box
        // if any terms aren't found, passTest is set to and remains false
        passTest = passTest && (item.toLowerCase().indexOf(term.toLowerCase()) > -1); 
      });
      // Add item to return array only if passTest is true -- all search terms were found in item
      if (passTest) { arrayToReturn.push(item); }
    });

    return arrayToReturn;
  }
})

and use it in place of filter: query:

<tr ng-repeat="thing in blah | and:query">

Plunker Demo

OTHER TIPS

My solution. It takes advantage of Angulars filterFilter and has 3 advantages over the chosen answer:

  • It searches objects too (not only strings)
  • It can be any number and kind of whitespace between search terms
  • Code is a few lines shorter

Here is the code:

  app.filter('multiple', ['filterFilter', function (filterFilter) {
    return function (items, query) {
      if (!query) return items;

      var terms = query.split(/\s+/);
      var result = items;
      terms.forEach(function (term) {
        result = filterFilter(result,term);
      });

      return result;
    }
  }]);

The accepted answer by Marc helped me as well, however, when using objects rather than strings you need to use dot notation to access the specific values. (for example 'name' and 'title')

items.forEach(function(item){ // iterate through array of items
    var passTest = true;
    var found = false;
    terms.forEach(function(term){ // iterate through terms found in query box
        // if any terms aren't found, passTest is set to and remains false
        found = (item.name.toLowerCase().indexOf(term.toLowerCase()) > -1)
            || (item.title.toLowerCase().indexOf(term.toLowerCase()) > -1); 
        passTest = passTest && found;
    });
    // Add item to return array only if passTest is true -- all search terms were found in item
    if (passTest) { arrayToReturn.push(item); }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top