Search code examples
angularjsangularjs-filter

AngularJS: Pass Filter conditions dynamically


I want to pass my filter conditions through dropdown menu to ng-repeat

<select class="form-control" ng-model="currentlySelected" ng-change="DropDownChnaged()">
    <option value ="">All</option>
    <option value="| filter : {deleted_at: null}">Active</option>
    <option value="| filter : {deleted_at: '!!'}">Inactive</option>
</select>

View

<tr ng-repeat="user in users {currentlySelected}">

Controller:

$scope.DropDownChnaged = function () {
    $scope.DropDownStatus = $scope.currentlySelected;
    alert(currentlySelected.DropDownChnaged);
};

When I pass set filter manually it works fine but when I try to pass dynamically its not working.


Solution

  • You may have already figured this out, but here is one way you could write a custom filter and then use it to filter your list of users. A custom filter should return a function that takes the collection as the first parameter and the filter criteria as the second parameter (you can add additional parameters if you would like to pass multiple filter criteria). This example uses the built-in .forEach of the collection you pass in. A check at the beginning ensures that both the collection and a filter criteria have been passed to the filter.

    angular.module('app', [])
      .filter('userFilter', () => {
        return (userList, filter) => {
          if (!userList || !filter) {
            return userList;
          }
          var out = [];
          userList.forEach((user) => {
            if (filter === 'active') {
              if (user.deleted_at === null) {
                out.push(user);
              }
            } else {
              if (user.deleted_at !== null) {
                out.push(user);
              }
            }
          });
          return out;
        }
      })
      .controller('ctrl', ($scope) => {
        $scope.users = [{
          name: 'John',
          deleted_at: null
        }, {
          name: 'Terry',
          deleted_at: '1/1/2018'
        }, {
          name: 'Joan',
          deleted_at: null
        }];
      });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
    <div ng-app="app" ng-controller="ctrl">
      <select class="form-control" ng-model="currentlySelected">
        <option value="">All</option>
        <option value="active">Active</option>
        <option value="inactive">Inactive</option>
      </select>
      <div>
        <ul>
          <li ng-repeat="user in users | userFilter:currentlySelected">{{user.name}}</li>
        </ul>
      </div>
    </div>

    Update If you would rather put this in the controller it's slightly different because the filter method will get called for each item and expects a boolean result (true to include the item, false to exclude it). Here is how you would write the $scope method in your controller:

    $scope.userFilter = (filter) => {
      return (user) => {
        if(!filter) return true;
        if (filter === 'active') {
          return user.deleted_at === null;
        } else {
          return user.deleted_at !== null;
        }
      }
    }
    

    And here's how you would use it in your ng-repeat:

    <li ng-repeat="user in users | filter:userFilter(currentlySelected)>{{user.name}}</li>