AngularJS 按属性数组过滤项目(复选框)

AngularJS filter items by array of properties (checkbox)

我想按多个属性筛选结果。 我的代码:

(function () {
  'use strict';
  angular.
  module('myApp', []).
  filter('byFeatures', byFeatures).
  controller('MyCtrl', MyCtrl);

  function byFeatures() {
    return function (items, conditions) {
      if (Object.getOwnPropertyNames(conditions).length === 0) {
        return items;
      }
      var filtered = [];
      for (var i = 0; i < items.length; i++) {
        var item = items[i];
        angular.forEach(item.features, function (feature) {
          if (conditions[feature.name] !== undefined && conditions[feature.name][feature.value] !== undefined) {
            if (conditions[feature.name][feature.value]) {
              //filtered.push(item);
              filtered[item.id] = item;
            }
          }
        });
      }
      //console.log(filtered);
      return filtered;
    };
  };

  function MyCtrl($scope, $filter) {
    $scope.allProducts = [{
        id: 0,
        name: "Product A",
        features: [{
            name: "Brand",
            value: "Apple"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 1,
        name: "Product B",
        features: [{
            name: "Brand",
            value: "Apple"
          },
          {
            name: "Memory",
            value: "32"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 2,
        name: "Product C",
        features: [{
            name: "Brand",
            value: "Nokia"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 3,
        name: "Product A",
        features: [{
            name: "Brand",
            value: "Samsung"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
    ];
    $scope.filters = [{
        name: "Brand",
        values: [
          "Apple",
          "Nokia",
          "Samsung",
        ]
      },
      {
        name: "Memory",
        values: [
          "16",
          "32",
        ]
      },
    ];
    $scope.currentFilter = {};
    $scope.$watch('currentFilter', function (newValue, oldValue, scope) {
      //console.log(newValue);

      $scope.products = $filter('byFeatures')($scope.allProducts, newValue);
    }, true);

  };
}());
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
  <title></title>
</head>

<body ng-app="myApp" class="ng-scope">
  <div ng-controller="MyCtrl" style="width: 100%;">
    
    <div style="width: 50%; float: left;">
      <h2>Available Phones</h2>
      <div ng-repeat="product in products">
        <h3>
          {{ product.name }}
        </h3>
        <ul>
          <li ng-repeat="feature in product.features">
            {{feature.name}} : {{feature.value}}
          </li>
        </ul>
       </div>
    </div>
    <div style="width: 50%; float: left;">
      <h2>Filters</h2>
      <pre>{{currentFilter|json}}</pre>
      <div ng-repeat="filter in filters">
        <span>{{filter.name}}</span>
        <ul>
          <li ng-repeat="value in filter.values">
            <input type="checkbox" ng-model="currentFilter[filter.name][value]"> {{value}}<br>
          </li>
        </ul>
      </div>
    </div>
</div>


</body></html>

如果我按品牌 "Apple" 过滤,显示 2 phone 品牌 "apple"(16 和 32 内存)- 没问题。但是,如果我按内存“16”添加第二个过滤器 - 将必须仅显示 1 phone 个内存为“16”的苹果。 怎么做? . Link 至 JSFiddle

问题是您所做的与您想要的相反:您正在检查产品是否包含 一个 项目的有效 属性(品牌内存)。我们需要做的是检查产品是否对所有项(品牌内存)有效属性。

只需更改函数内的循环 byFeatures 即可找到每个相关条件(当其值为真时!)并确保我们的产品具有品牌和记忆中的每个选定属性之一.在这里您可以看到正确的片段:

(function () {
  'use strict';
  angular.
  module('myApp', []).
  filter('byFeatures', byFeatures).
  controller('MyCtrl', MyCtrl);

  function byFeatures() {
    return function (items, conditions) {
      if (Object.getOwnPropertyNames(conditions).length === 0) {
        return items;
      }
      var filtered = [];
      for (var i = 0; i < items.length; i++) {
        var item = items[i],
          hasProperties = true;

        angular.forEach(conditions, function (value, key) {
          for (var i = 0; i < item.features.length; i++) {
            if (item.features[i].name === key && (!value.hasOwnProperty(item.features[i].value) || !value[item.features[i].value])) {
              for (var j in value) {
                if (value[j]) {
                  hasProperties = false;
                }
              }
            }
          }
        });

        if (hasProperties) {
          filtered.push(item);
        }
      }
      //console.log(filtered);
      return filtered;
    };
  };

  function MyCtrl($scope, $filter) {
    $scope.allProducts = [{
        id: 0,
        name: "Product A",
        features: [{
            name: "Brand",
            value: "Apple"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 1,
        name: "Product B",
        features: [{
            name: "Brand",
            value: "Apple"
          },
          {
            name: "Memory",
            value: "32"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 2,
        name: "Product C",
        features: [{
            name: "Brand",
            value: "Nokia"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
      {
        id: 3,
        name: "Product A",
        features: [{
            name: "Brand",
            value: "Samsung"
          },
          {
            name: "Memory",
            value: "16"
          },
          {
            name: "Color",
            value: "Black"
          }
        ]
      },
    ];
    $scope.filters = [{
        name: "Brand",
        values: [
          "Apple",
          "Nokia",
          "Samsung",
        ]
      },
      {
        name: "Memory",
        values: [
          "16",
          "32",
        ]
      },
    ];
    $scope.currentFilter = {}; //$scope.filters;
    $scope.$watch('currentFilter', function (newValue, oldValue, scope) {
      $scope.products = $filter('byFeatures')($scope.allProducts, newValue);
    }, true);

  };
}());
<html>

<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
  <script src="js/script.js"></script>
  <title></title>
</head>

<body ng-app="myApp" class="ng-scope">
  <div ng-controller="MyCtrl" style="width: 100%;">
    <div style="width: 50%; float: left;">
      <h2>Available Phones</h2>
      <div ng-repeat="product in products">
        <h3>
          {{ product.name }}
        </h3>
        <ul>
          <li ng-repeat="feature in product.features">
            {{feature.name}} : {{feature.value}}
          </li>
        </ul>
      </div>
    </div>
    <div style="width: 50%; float: left;">
      <h2>Filters</h2>
      <pre>{{currentFilter|json}}</pre>
      <div ng-repeat="filter in filters">
        <span>{{filter.name}}</span>
        <ul>
          <li ng-repeat="value in filter.values">
            <input type="checkbox" ng-model="currentFilter[filter.name][value]"> {{value}}<br>
          </li>
        </ul>
      </div>
    </div>
  </div>
</body>

</html>

我还更改了您将新产品添加到筛选数组的方式。否则,如果唯一项的 ID 为 2,则数组会将前 2 个位置保留为 'undefined',这会导致 ngRepeat 迭代出现问题