Search code examples
javascriptangularjsangular-filters

ng-show working with multiple filters in ng-repeat


I have an ng-repeat list with multiple filters, but as I need the elements to be hidden and not removed from the DOM, I use ng-show for the filtering.

This is how my first filter look like:

<a href="" ng-click="myFilter = ''; toggle = toggle=0; togglesec=0; mySecondFilter = {}" ng-class="{'active' : toggle==0}" >
   Tot
</a>

<a href="" ng-click="myFilter = 'pa'; toggle = toggle=1;  togglesec=0;  mySecondFilter = {}" ng-class="{'active' : toggle==1}">
   Pa
</a>

<a href="" ng-click="myFilter = 'Reposteria'; toggle = toggle=2; togglesec=0; mySecondFilter = {}" ng-class="{'active' : toggle==2}">
   Reposteria
</a>

And the second one:

<div ng-init="togglesec=0; mySecondFilter = {}">
   <a ng-click="mySecondFilter = {}; togglesec = togglesec=0" ng-class="{'active' : togglesec==0}">
       All
   </a>
   <a ng-click="mySecondFilter = {'vegan': true}; togglesec = togglesec=1" ng-class="{'active' : togglesec==1}">
       Vegan
   </a>
   <a ng-click="mySecondFilter = {'gluten': true}; togglesec = togglesec=2" ng-class="{'active' : togglesec==2}">
       Gluten Free
   </a>
</div>

Now, I was able to filter the ng-repeat using ng-show and the first filter like so:

<div ng-repeat="pa in products" ng-show="pa.tipus.indexOf(myFilter) != -1">

Basically it compares the value of myFilter with the pa.tipus object property, and it works OK.

But it won't work with the second filter, because mySecondFilter is an object, not a string (it needs to filter the results containing vegan:true or gluten:true)

Here's an example of my object type:

pa {
    tipus : 'pa',
    gluten : false,
    vegan : true
}

Any tips on how to combine both filters in the same ng-show?

EDIT

I've applied the answer by Naren, but I get the following error on click on any filter:

angular.min.js:122 TypeError: Cannot create property 'vegan' on string ''.

I've also tried to initialize myFilter by adding this, but no luck, same error appears:

$scope.myFilter = {
  tipus : '',
  vegan : '',
  gluten : '',
  lactosa : ''
};

Solution

  • Update:

    Since the user wanted a generic version for the filtering. The following function should be the answer.

    $scope.validate = function(row) {
        for (var key in $scope.myFilter) {
          if ($filter('filter')([row], {
              [key]: $scope.myFilter[key]
            }).length === 0) {
            return false;
          }
        }
        return true;
      }
    

    Where we loop through an object where all the filters are stored, then return false if any of the filters are not satisfied.

    Please check the below example to get a understanding of how the filter works.

    JSFiddle Demo

    Old:

    Here is my version of the fix. Angular's $filter will be great for identifying the object with the property, but this is not possible to have written in the HTML, hence I call a function which will return true or false to the ng-show.

      $scope.validate = function(row) {
        if (row.tipus.indexOf($scope.myFilter) != -1) {
          if ($filter('filter')([row], $scope.mySecondFilter).length !== 0) {
            return true;
          } else {
            return false;
          }
        } else {
          return false;
        }
      }
    

    Let me explain the function. First we receive the row of the ng-repeat through the parameter of validate, after which I apply the first if condition which is basically whatever you had written earlier, this code works great btw. Then I check the row using the $filter syntax for the object present in $scope.mySecondFilter, Refer here for more on filtering with $filter, this will basically check if the row passed contains the required object property and return true or false.

    Here is a working example of your code for reference.

    JSFiddle Demo

    Please let me know if this fixes your issue completely :)