如何根据来自另一个对象的匹配值过滤或自定义过滤对象数组

时间:2015-03-11 15:18:47

标签: json angularjs

我在AngularJS中使用了15个输入字段实现了高级搜索。

在页面加载中,结果集以 JSON格式从数据库返回,我只需要在客户端中进行过滤。

输入条件的等效列在结果集中可用,我只需要检查其各自的列。

我正在按JSON.stringify()转换每一列,并使用下面的搜索参数进行检查:

$scope.filteredData = $scope.actualData.filter(function(item) {
    return JSON.stringify(item.FirstName).toLowerCase().indexOf(lowerFirstName) != -1 &&
    JSON.stringify(item.LastName).toLowerCase().indexOf(lowerLastName) != -1 &&
    JSON.stringify(item.EmailAddress).toLowerCase().indexOf(lowerEmailAddress) != -1 &&
    JSON.stringify(item.Address1).toLowerCase().indexOf(lowerAddress1) != -1 &&
    JSON.stringify(item.Address2).toLowerCase().indexOf(lowerAddress2) != -1;
    ...... etc // upto 15 fields
});

由于我有15个输入字段,实际结果集至少包含50,000条记录。

因此,按JSON.stringify()转换每个记录的每一列并使用搜索参数检查肯定会导致性能问题。

还有其他方法可以通过其他方法在客户端实现过滤。

我在Plunker中发布了一个示例代码,仅包含5个输入字段:http://plnkr.co/edit/nUWZEbGvz7HG6gb91YZP

2 个答案:

答案 0 :(得分:2)

sylwester的答案是你过滤事物的正常方式。您的代码看起来只想过滤到与每个输入字段匹配的对象。您编写代码尝试查找每个属性与searchParams对象匹配的对象。那时,我没有看到找到该对象有什么好处,因为用户已经再次创建了该对象!尽管如此,这是您的代码的正确版本:

Live demo here.

<div ng-repeat="data in actualData | filter:searchData()">
 $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).every(function(key) {
        // skip the $$hashKey property Angular adds to objects
        if (key === '$$hashKey') { return true; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        return item[key].toLowerCase() === $scope.searchParams[searchKey].toLowerCase();
      });
    };
  };

出于浏览器和服务器的缘故,您确实需要限制来自服务器的数据。实现LIMIT,OFFSET系统很容易。听起来总的来说,您只需要能够在服务器上查询某个记录。

根据您的评论,您似乎肯定希望Angular内置过滤器filter:searchParams,并且只需将searchParams模型大写以匹配您的数据。为了好玩,我将提供更多选项以进行更精细的调整。

这个几乎模仿filter:searchParams。您可以更改> 1以在部分匹配开始时进行调整,或仅在两个项严格相等===时才返回true以禁用部分匹配。这里的区别在于所有项目都会被隐藏,直到匹配为止,而filter:searchParams会显示所有项目,然后删除不匹配的内容。

Live demo here.

  $scope.searchData = function() {
    return function(item) {
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length > 1 && match;
      });
    };
  };

最后,为了完全模仿filter:searchParams,你只需要检查以不过滤项目,直到有用户输入并且输入足够长以开始部分匹配。

Live demo here.

  $scope.searchData = function() {
    var partialMatchLength = 2;
    return function(item) {
      var shouldFilter = Object.keys($scope.searchParams).some(function(key) {
        return $scope.searchParams[key] && $scope.searchParams[key].length >= partialMatchLength;
      });
      if (!shouldFilter) { return true; }
      return Object.keys(item).some(function(key) {
        if (key === '$$hashKey') { return false; }
        var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
        var currentVal = $scope.searchParams[searchKey].toLowerCase();
        var match = item[key].toLowerCase().match(currentVal);
        return currentVal.length >= partialMatchLength && match;
      });
    };
  };

答案 1 :(得分:1)

首先,你有{000}记录的ng-repeter更有可能会杀死你的浏览器,所以你应该关注分页。 其次,您可以使用角度过滤器轻松过滤数据,请参阅演示

http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview

<div ng-controller="ListCtrl">
    <br />
    First Name:
    <input type="text" id="txtFirstname" ng-model="searchParams.FirstName">
    <br/>Last Name:
    <input type="text" id="txtLastname" ng-model="searchParams.LastName">
    <br/>Email Address:
    <input type="text" id="txtEmailAddress" ng-model="searchParams.EmailAddress">
    <br/>Address 1:
    <input type="text" id="txtAddress1" ng-model="searchParams.Address1">
    <br/>Address 2:
    <input type="text" id="txtAddress2" ng-model="searchParams.Address2">
    <br/>
    <button class="btn btn-primary" ng-click="searchData()">Search</button>
    <br />
    <hr />
    <b>Filtered Data(s):</b>
    <div ng-repeat="data in actualData | filter:searchParams ">
      <span ng-bind="data.FirstName"></span>
      <span ng-bind="data.LastName"></span> |
      Address : {{data.Address1}}
    </div>
    <hr />

  </div>