简体   繁体   English

角度自定义过滤器到复杂对象

[英]Angular custom filter to complex object

I have a $scope.users that I use to show a table and I need to apply a filter with multiple options, 我有一个$scope.users用于显示表格,我需要应用具有多个选项的过滤器,

Here is the $scope.users object: 这是$scope.users对象:

[
  {
    "login": "andres.un1@mail.com",
    "merchant": {
      "merchantId": 500095,
      "status": "ENABLED",
      "defaultAccountId": null,
      "accounts": {
        "500092": "ADMIN",
        "500178": "CONSULT",
        "500180": "ADMIN",
        "500182": "ADMIN",
        "500201": "ADMIN"
      }
    },    
    "name": "Carlos"    
  },
  {
    "login": "andres.un2@mail.com",
    "merchant": {
      "merchantId": 500095,
      "status": "DISABLED",
      "defaultAccountId": null,
      "accounts": {
        "500092": "CONSULT",
        "500178": "MANAGER",
        "500180": "ADMIN",
        "500182": "ADMIN",
        "500201": "ADMIN"
      }
    },
    "name": "Carlos Andres"
  },
  {
    "login": "cosme.fulanito@mail.com",
    "merchant": {
      "merchantId": 500095,
      "status": "DISABLED",
      "defaultAccountId": null,
      "accounts": {
        "500092": "CONSULT",
        "500178": "MANAGER",
        "500180": "ADMIN",
        "500182": "ADMIN",
        "500201": "ADMIN"
      }
    },
    "name": "Cosme"    
  }
]

In the filter I pass other object from the $scope to filter the data, in this case is $scope.searchParams that I previously calculate in a directive. 在过滤器中,我从$scope传递其他对象来过滤数据,在这种情况下是我之前在指令中计算的$scope.searchParams

$scope.searchParams : $scope.searchParams

[
  {'name':'Cosme'},
  {'login':'andres.un1@mail.com'},
  {'status':'ENABLED'},
  {'status':'DISABLED'},
  {'account':'267123'},
  {'account':'543987'},
  {'account':'544111'},
  {'account':'543987'}
]

As you can see, name and login are unique in the filter, but status and account can have multiple values to apply in the filter. 如您所见, namelogin在过滤器中是唯一的,但statusaccount可以在过滤器中应用多个值。 Here is my approach to do that but I think is very ineffective, also is not complete because doesn't have the multiple filter functionality: 这是我的方法,但我觉得非常无效,也不完整,因为没有多重过滤功能:

var secUser = function () {

  return function (input, list) {

    var out = [];

    var nameArr = [],
      loginArr = [],
      statusArr = [],
      profileArr = [],
      accountsArr = [];

    angular.forEach(list, function(filter){
      console.log(filter);
      if(filter.hasOwnProperty('name')){
        nameArr.push(filter.name);
      }
      if(filter.hasOwnProperty('login')){
        loginArr.push(filter.login);
      }
      if(filter.hasOwnProperty('status')){
        statusArr.push(filter.status);
      }
      if(filter.hasOwnProperty('account')){
        accountsArr.push(filter.account);
      }
      if(filter.hasOwnProperty('profile')){
        profileArr.push(filter.profile);
      }
    });

    angular.forEach(input, function(user){

      // no filters applied
      if(nameArr.length < 1 && loginArr.length < 1 &&
        statusArr.length < 1 && accountsArr.length < 1 &&
        profileArr.length < 1){
        out.push(user);
      }
      // filters to be applied
      else{
        if(nameArr.indexOf(user.name) > -1){
          out.push(user);
        }
        if(loginArr.indexOf(user.login) > -1){
          out.push(user);
        }
        if(statusArr.indexOf(user.merchant.status) > -1){
          out.push(user);
        }
      }

    });

    return out;
  };
};
//-- register filter
app.filter('secUser', secUser);

Finally here is how I am using the fiter: <tbody ng-repeat="user in users | secUser:searchParams " class="table-striped"> 最后,这里是我如何使用fiter: <tbody ng-repeat="user in users | secUser:searchParams " class="table-striped">

¿Is there a better way to implement this filter considering that in the future there can be more filter fields? ¿考虑到将来可以有更多的过滤器字段,是否有更好的方法来实现此过滤器? Also I think is very coupled with the view. 另外我认为与观点非常相配。

There are multiple ways you could do this but one requirement is you need to make your searchParams structure more generic. 有多种方法可以做到这一点,但有一个要求是你需要使searchParams结构更通用。 For example, here I'm using an object where each key is the path to the target object and the corresponding value is an array with all the values you want to match against: 例如,这里我使用的是一个对象,其中每个键都是目标对象的路径,相应的值是一个包含要匹配的所有值的数组:

$scope.searchParams = {
  'name': ['Cosme'],
  'login': ['andres.un1@mail.com'],
  'merchant.status' : ['ENABLED','DISABLED'],
  'merchant.accounts' : ['267123','543987 ','544111','543987'],
}

Then you can update your filter to handle generic data. 然后,您可以更新过滤器以处理通用数据。 It can't be completely generic because it does depend on your business logic, eg does accounts match on the key 500092 or the value CONSULT . 它不能完全通用,因为它取决于您的业务逻辑,例如,密钥500092或值CONSULT上的accounts匹配。 Here is an updated filter function handling the three kinds of targets in your data: 这是一个更新的过滤器函数,用于处理数据中的三种目标:

  • primitive values match the value eg name 原始值匹配值,例如name
  • arrays match any of the contents eg status 数组匹配任何内容,例如status
  • objects match any of the keys eg accounts 对象匹配任何键,例如accounts

JsFiddle (with data slightly modified for testing) JsFiddle (稍微修改数据以进行测试)

var secUser = function () {
  return function (users, filters) {

    return users.filter(function(user){
      var match = false;

      angular.forEach(filters, function(filterValues, keyPath){
        if (match) return; // if we already found a match, don't continue searching

        // get the target based on the contents of the keypath
        var target = keyPath.split('.').reduce(function(object, key) {
          // get the next part of the path, if exists
          return object && object[key];
        }, user); // initial value is the user object

        if (target !== undefined){ // if the target exists for this item
          var values = []; // stores the values from the item to search against

          if(typeof target === "object") {
            values = Object.keys(target);            
          }
          else if (target.isArray) {
            values = target;
          } else {
            values = [target];
          }

          // check if any entry in values matches any entry of the filter values
          match = values.some(function (v) {
            return filterValues.indexOf(v) >= 0;
          });
        }
      });

      return match;
    });
  };
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM