Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: filter in controller on all field except one field

In my angularjs app i get via json such example of data:

{"id":"1a", "name": "aaa", "emails": {{"[email protected]"}, {"[email protected]"}}},
{"id":"2a", "name": "aba", "emails": {{"[email protected]"}, {"[email protected]"}}},
{"id":"3a", "name": "aab", "emails": {{"[email protected]"}, {"[email protected]"}}},

and for performance reasons i didn't use filter for ng-repeat, but use ng-show schema...

so in controller i have such code (search is my inputs value):

  $scope.$watch('search', function(newVal, oldVal) {
    $scope.filteredArray = $filter('filter')($scope.users, $scope.search, newVal);
  });

but it search even in id's, for example i enter a and get it from id, but i do not need field id here...

So how to search with filter only in specific fields?

like image 670
brabertaser19 Avatar asked Feb 10 '23 19:02

brabertaser19


1 Answers

If you care about performance, probably the best choice would be not to use $filter('filter') at all. Assuming your data is a JSON you can do the following:

function contains(src, value, except) {
  var key;
  switch(typeof src) {
    case 'string':
    case 'number':
    case 'boolean':
      return String(src).indexOf(value) > -1;
    case 'object':
      except = except || [];
      for(key in src) {
        if( src.hasOwnProperty(key) &&
            except.indexOf(key) < 0 &&
            contains(src[key], value, except)
        ) {
          return true;
        }
      }
  }
  return false;
}

angular.module('app', []).
  factory('appService', function() {
    var data = [
      {"id":"1a", "name": "aaa", "emails": ["[email protected]", "[email protected]"]},
      {"id":"2a", "name": "aba", "emails": ["[email protected]", "[email protected]"]},
      {"id":"3a", "name": "aab", "emails": ["[email protected]", "[email protected]", ["[email protected]", "[email protected]"]]}
    ];
    return {
      getFilteredData: function(filter, except) {
        return filter ? data.filter(function(item) {
          return contains(item, filter, except)
        }) : data.slice(0);
      }
    }
  }).
  controller('appController', ['$scope', 'appService', function($scope, appService) {
    $scope.search = '';
    $scope.$watch('search', function(val) {
      $scope.data = appService.getFilteredData(val, ['id']);
    });
  }]);
<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="appController">
    <input ng-model="search" ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"/>
    <ul>
      <li ng-repeat="item in data">{{::item}}</li>
    </ul>
  </body>

</html>

Code above will make a deep search in all fields of data and it's items excluding list of fields passed as parameter (in this example ['id'])

Tip #1: Implementing business logic inside controller is kind of bad practice in Angular, which has services for that purpose.

Tip #2: If you have large data-sets to be displayed, debouncing filter change will be very beneficial from performance point of view.

Tip #3: If your data-set items are immutable, you can take advantage of one-time binding (using {{::item}} syntax) and speed-up your app by reducing number of watches created by Angular.

like image 118
Vadim Avatar answered Feb 13 '23 15:02

Vadim