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 迭代出现问题
我想按多个属性筛选结果。 我的代码:
(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 迭代出现问题