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

时间:2016-09-09 16:45:00

标签: javascript angularjs filter

我有$scope.users用于显示表格,我需要应用具有多个选项的过滤器,

这是$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"    
  }
]

在过滤器中,我从$scope传递其他对象来过滤数据,在这种情况下是$scope.searchParams,我之前在指令中计算过。

$scope.searchParams

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

如您所见,namelogin在过滤器中是唯一的,但statusaccount可以在过滤器中应用多个值。这是我的方法,但我觉得非常无效,也不完整,因为没有多重过滤功能:

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);

最后,我是如何使用fiter:<tbody ng-repeat="user in users | secUser:searchParams " class="table-striped">

¿考虑到将来可以有更多的过滤器字段,是否有更好的方法来实现此过滤器?另外我认为与观点非常相配。

1 个答案:

答案 0 :(得分:1)

有多种方法可以做到这一点,但有一个要求是你需要使searchParams结构更通用。例如,这里我使用的是一个对象,其中每个键都是目标对象的路径,相应的值是一个包含您想要匹配的所有值的数组:

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

然后,您可以更新过滤器以处理通用数据。它不能完全通用,因为它取决于您的业务逻辑,例如accounts上的500092或值CONSULT是否匹配。这是一个更新的过滤器函数,用于处理数据中的三种目标:

  • 原始值匹配值,例如name
  • 数组匹配任何内容,例如status
  • 对象匹配任何键,例如accounts

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;
    });
  };
};