2016-10-07 6 views
-1

Я хочу изменить этот продукт угловую/JavaScript фильтрУгловое/JavaScript фильтр продуктов

Когда пользователь выбирает, например: Процессор - 2 ГГц и памяти - 32GB Я хочу показать только продукт, который имеют все те свойства, ,

В настоящий момент фильтр отображает все продукты с частотой 2 ГГц и всеми продуктами с 32 ГБ.

Plunker https://plnkr.co/edit/vr9o2aHkHvCL1cvgKILd?p=preview

angular.module('app', []) 
 
     .controller('Controller', function($scope) { 
 
     $scope.items = [{ 
 
      "name": "Product - 2GHZ, 32GB, Black", 
 
      "tags": [{ 
 
      "category": 1, 
 
      "tag": 2 
 
      }, { 
 
      "category": 2, 
 
      "tag": 4 
 
      }, { 
 
      "category": 3, 
 
      "tag": 8 
 
      }] 
 
     }, { 
 
      "name": "Product - 2GHz, 128GB, Black", 
 
      "tags": [{ 
 
      "category": 1, 
 
      "tag": 2 
 
      }, { 
 
      "category": 2, 
 
      "tag": 5 
 
      }, { 
 
      "category": 3, 
 
      "tag": 8 
 
      }] 
 
     }, { 
 
      "name": "Product - 1GHz, 128GB, White", 
 
      "tags": [{ 
 
      "category": 1, 
 
      "tag": 1 
 
      }, { 
 
      "category": 2, 
 
      "tag": 5 
 
      }, { 
 
      "category": 3, 
 
      "tag": 7 
 
      }] 
 
     }]; 
 

 
     $scope.items_dup = $scope.items 
 
      // checkbox selection 
 
     $scope.selectionTag = []; 
 
     $scope.selectionCat = []; 
 
     $scope.toggleSelection = function toggleSelection(tag, category) { 
 
      var idxTag = $scope.selectionTag.indexOf(tag); 
 
      if (idxTag > -1) { 
 
      $scope.selectionTag.splice(idxTag, 1); 
 
      } else { 
 
      $scope.selectionTag.push(tag); 
 
      } 
 
      // this is not working, probably need twodimensional array 
 
      // category 
 
      var idxCat = $scope.selectionCat.indexOf(category); 
 
      if (idxCat > -1) { 
 
      $scope.selectionCat.splice(idxCat, 1); 
 
      } else { 
 
      $scope.selectionCat.push(category); 
 
      } 
 
     }; 
 

 
     // filter list 
 
     $scope.filter = function() { 
 
      filterTag($scope.selectionTag, $scope.items); 
 

 
      function filterTag(selected, items) { 
 
      var out = []; 
 
      angular.forEach(items, function(value, key) { 
 
       angular.forEach(selected, function(inner_value, key) { 
 
       angular.forEach(value.tags, function(inner_value2, key) { 
 
        if (value.tags[key].tag === inner_value) { 
 
        if (out.indexOf(value) == -1) { 
 
         out.push(value) 
 
        } 
 
        } 
 
       }) 
 
       }) 
 
      }) 
 
      if (out.length > 0) { 
 
       $scope.items_dup = out; 
 
      } else { 
 
       $scope.items_dup = $scope.items; 
 
      } 
 
      } 
 

 
     }; 
 
     })
<!DOCTYPE html> 
 
<head> 
 
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script> 
 
    <script src="script.js"></script> 
 
</head> 
 
<body ng-app="app"> 
 
    <div ng-controller="Controller"> 
 
    <h1>Product filtering!</h1> 
 
    <li ng-repeat="item in items_dup"> 
 
     {{item.name}} 
 
    </li> 
 
    <hr> 
 
    <p data-category="1">Processor</p> 
 
    <label> 
 
     <input type="checkbox" value="1" ng-click="toggleSelection(1,1)"> 1GHz 
 
    </label> 
 
    <br> 
 
    <label> 
 
     <input type="checkbox" value="2" ng-click="toggleSelection(2,1)"> 2GHz 
 
    </label><br> 
 
    <hr> 
 
    <p data-category="2">Memory</p> 
 
    <label> 
 
     <input type="checkbox" value="4" ng-click="toggleSelection(4,2)"> 32GB 
 
    </label> 
 
    <br> 
 
    <label> 
 
     <input type="checkbox" value="5" ng-click="toggleSelection(5,2)"> 128GB 
 
    </label><br> 
 
    <hr> 
 
    <p data-category="3">Color</p> 
 
    <label> 
 
     <input type="checkbox" value="7" ng-click="toggleSelection(7,3)"> White 
 
    </label> 
 
    <br> 
 
    <label> 
 
     <input type="checkbox" value="8" ng-click="toggleSelection(8,3)"> Black 
 
    </label><br> 
 
    <br><br> 
 
    <button ng-click="filter()">Filter list</button> 
 
    </div> 
 
</body> 
 
</html>

ответ

0

Вы можете использовать Array#every, чтобы проверить, если каждый выбор появляется в списке тэга элемента. Если вы хотите переключиться с and на фильтр or, вы можете вместо этого использовать Array # some.

Хорошая вещь об этих методах заключается в том, что они возвращаются, как только они знают их результат, заканчивая цикл, когда это возможно.

$scope.filter = function() { 
    $scope.items_dup = $scope.items.filter(function(item) { 
    return $scope.selectionCat.every(function(c) { 
     return item.tags 
     .some(function(t) { 
      return t.category === c && 
      $scope.selectionTag.indexOf(t.tag) !== -1; 
     }); 
    }) 

    }); 
} 

В plunker: here

Пример того, как можно создать карту, и как это повлияет на ваш фильтр:

var $scope.items = [ /* ... */ ].map(function(item) { 
    var tagMap = item.tags.reduce(function(result, t.tag) { 
    result[t.tag] = true; // Add the tag Id to the map 
    return result; 
    }, {}); 

    // Add the tag map to the item 
    return Object.assign(item, { tagMap: tagMap }); 

}); 

// Now, you can filter like so: 
var matches = selectedTagIds.every(function(id) { 
    return item.tagMap[id]; 
}); 
+0

спасибо, но не работаем. Когда я выбираю 1 ГГц и черный цвет, он показывает все продукты, но я хочу, чтобы продукт имел 1 ГГц ** и ** черный цвет. И в этом примере нет продукта с этими спецификациями. – akuljana

+0

Эта логика уже была в вашем собственном примере: если нет совпадения, покажите все продукты. 'if (out.length> 0) { $ scope.items_dup = out; } else { $ scope.items_dup = $ scope.items; } 'Если вы не хотите этого поведения, замените оператор' else', чтобы установить пустой массив, или просто установите 'out' без проверки его длины. – user3297291

+0

, что логика не работает, как ожидалось. Прямо сейчас, когда пользователь выбирает, например, ** 2 ГГц ** и ** 128 ГБ ** (пожалуйста, попробуйте здесь: https://plnkr.co/edit/vr9o2aHkHvCL1cvgKILd?p=preview) фильтр показывает ** все ** продукт с 2 ГГц или 128 ГБ.Но я хочу, чтобы продукт имел 2 ГГц ** и ** 128 ГБ, и только один продукт, например, имел эти спецификации. Надеюсь, я объяснил это лучше на этот раз :) – akuljana

0

другой подход с использованием фильтра с объектом фильтра на ng-repeat, в этом случае элементы отфильтровываются сразу же при изменении состояния флажков:

<li ng-repeat="item in items_dup | filter : mainFilter : true"> 
    {{item.name}} 
</li> 

все флажки использовать нг-модель и обновления запуска функции: функцию

<label> 
    <input type="checkbox" ng-change="updateFilters()" ng-model="filters.processor['1GHZ']"> 1GHz 
</label> 

обновление:

$scope.updateFilters = function updateFilters() { 
     $scope.mainFilter = {}; 
     angular.forEach($scope.filters, function (category, categoryKey) { 
     angular.forEach(category, function (value, valueKey) { 
      if (value) { 
      if ($scope.mainFilter[categoryKey]) { 
       delete $scope.mainFilter[categoryKey]; 
      } 
      else { 
       $scope.mainFilter[categoryKey] = valueKey; 
      } 
      } 
     }); 
     }); 
    }; 

каждый элемент имеет процессор, памяти и цвета атрибуты добавлены ,

plunker: https://plnkr.co/edit/6BDVYzV430N0MSaopGXt?p=preview

+0

спасибо, но он не работает, когда я добавляю еще один продукт с дополнительным цветом, например, красным. Plunker: https://plnkr.co/edit/BLqiFbTJOZ8r1Q2jz25S?p=preview Когда я выбираю красный и черный, он показывает все продукты. – akuljana

+0

Я немного изменил логику, см. Мой обновленный plunker https://plnkr.co/edit/6BDVYzV430N0MSaopGXt?p=preview, теперь он поддерживает любое количество свойств фильтра – Andriy

Смежные вопросы