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

187 Views Asked by At

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.

1

There are 1 best solutions below

0
Derek718 On

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.