2017-01-24 4 views
1

Я хотел бы отфильтровать результаты по нескольким свойствам. Мой код:Элементы фильтра AngularJS по массиву свойств (флажок)

(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>

Если я фильтр по марке "Яблоко" отображаются 2 телефона с брендом "яблоко" (16 и 32 памяти) - ее хорошо. Но если добавить второй фильтр по памяти «16» - отобразится только одно яблоко телефона с памятью «16». Как это сделать? , Ссылка на JSFiddle

ответ

0

Проблемы в том, что вы делаете противоположный от того, что вы хотите: Вы проверяете, что продукт содержит действительное свойство для одного пунктов (марка или памяти). Что нам нужно сделать, это проверить, имеет ли товар действительное свойство для все изделия (и Память).

Было бы достаточно изменить цикл внутри функции 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>

Я также изменил способ, которым Вы складывали новый продукт отфильтрованного массива. В противном случае, если идентификатор единственного элемента равен 2, массив сохранит первые 2 позиции как «неопределенные», и это вызовет проблемы через итерации ngRepeat