wombatdev
wombatdev

Reputation: 11

Angular filter table with search across two columns simultaneously

I have a table with multiple columns that I currently filter using a text input (search) field:

HTML (simplified):

<div class="search">
    <input type="text" placeholder="Search" data-ng-model="vm.filter_on" />
</div>
<tr data-ng-repeat="product in vm.data | filter: vm.filter_on>
    <td>{{product.id}}</td>
    <td>{{product.name}}</td>
    <td>{{product.brand}}</td>
</tr>

Let's say I have these three products:

{
id: 1,
name: "Waffles",
brand: "Walmart",
},
{
name: "Pizza",
brand: "Walmart",
},
{
name: "Soda",
brand: "Target",
}

If I enter "Walmart" in the search bar, I will see the first two objects. What I want to know is if it's possible to search "Walmart piz" and only be shown the second object--essentially, have the search term try to match across values from multiple columns.

Most of what I've found when looking for a solution has been about trying to set the specific columns a search will consider, but I haven't found anything that solves my exact use case.

I created a workaround using the nifty filter from this question, which solves the issue of searching with multiple fragments rather than full terms: AngularJS filter for multiple strings

But even then, I still need to combine the column data into a single string for the search to work. Is there any way to do this more elegantly in Angular?

Upvotes: 0

Views: 2254

Answers (1)

Slava Utesinov
Slava Utesinov

Reputation: 13488

You should create custom filter:

angular.module('app', []).controller('ctrl', function($scope) {
  var vm = this;
  vm.filter_on = "Walmart piz";
  vm.data = [
    { id: 1, name: "Waffles", brand: "Walmart" },
    { name: "Pizza", brand: "Walmart" },
    { name: "Soda",  brand: "Target" }
  ]
}).filter('custom', function(){
  return function(input, search){
    if(!search)
      return input;
      
    var items = search.split(' ').filter(x => x).map(x => x.toLowerCase());    
    return input.filter(x => {
      for(var item of items){
        var flag = false;        
        for(var prop in x){                  
          if(prop != '$$hashKey' && (x[prop] + '').toLowerCase().indexOf(item) != -1){
              flag = true;
              break;          
          }
        }
        if(!flag)
          return false;
      }
      return true;
    })
  }
})
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>

<div class="search" ng-app='app' ng-controller='ctrl as vm'>
  <input type="text" placeholder="Search" ng-model="vm.filter_on" />
  <br>
  <br>
  <table>
    <thead>
      <tr>
        <th>id</th>        
        <th>name</th>
        <th>brand</th>
      <tr>
    </thead>
    <tbody>
      <tr data-ng-repeat="product in vm.data | custom: vm.filter_on">
        <td>{{product.id}}</td>
        <td>{{product.name}}</td>
        <td>{{product.brand}}</td>
      </tr>
    </tbody>
  </table>
</div>

Upvotes: 1

Related Questions