如何使 ng- 重复过滤掉重复的结果

我在一个 JSON 文件上运行一个简单的 ng-repeat,并希望获得类别名称。大约有100件物品,每一件都属于一个类别——但是只有大约6个类别。

我现在的代码是这样的:

<select ng-model="orderProp" >
<option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>

输出是100个不同的选项,大部分是重复的。如何使用 Angular 检查 {{place.category}}是否已经存在,而不是创建一个选项,如果它已经存在?

编辑: 在我的 javascript,$scope.places = JSON data,只是为了澄清

226786 次浏览

如果您想列出类别,我认为您应该明确地声明您的 视野中的意图。

<select ng-model="orderProp" >
<option ng-repeat="category in categories"
value="\{\{category}}">
\{\{category}}
</option>
</select>

在控制器中:

$scope.categories = $scope.places.reduce(function(sum, place) {
if (sum.indexOf( place.category ) < 0) sum.push( place.category );
return sum;
}, []);

您可以使用 AngularUI 中的 独一无二过滤器(这里有源代码: AngularUI 唯一过滤器) ,并直接在 ng-options (或 ng-repeat)中使用它。

<select ng-model="orderProp" ng-options="place.category for place in places | unique:'category'">
<option value="0">Default</option>
// unique options from the categories
</select>

或者您可以使用 loash 编写自己的过滤器。

app.filter('unique', function() {
return function (arr, field) {
return _.uniq(arr, function(a) { return a[field]; });
};
});

您可以在 棱角过滤器模块中使用“惟一”(别名: uniq)过滤器

用途: colection | uniq: 'property'
您还可以通过嵌套属性进行筛选: colection | uniq: 'property.nested_property'

你能做的,就是这样. 。

function MainController ($scope) {
$scope.orders = [
{ id:1, customer: { name: 'foo', id: 10 } },
{ id:2, customer: { name: 'bar', id: 20 } },
{ id:3, customer: { name: 'foo', id: 10 } },
{ id:4, customer: { name: 'bar', id: 20 } },
{ id:5, customer: { name: 'baz', id: 30 } },
];
}

HTML: 我们根据客户 ID 进行过滤,即删除重复的客户

<th>Customer list: </th>
<tr ng-repeat="order in orders | unique: 'customer.id'" >
<td> \{\{ order.customer.name }} , \{\{ order.customer.id }} </td>
</tr>

结果
顾客名单:
Foo 10
第20小节
Baz 30

这个密码对我有用。

app.filter('unique', function() {


return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
})

然后

var colors=$filter('unique')(items,"color");

添加这个过滤器:

app.filter('unique', function () {
return function ( collection, keyname) {
var output = [],
keys = []
found = [];


if (!keyname) {


angular.forEach(collection, function (row) {
var is_found = false;
angular.forEach(found, function (foundRow) {


if (foundRow == row) {
is_found = true;
}
});


if (is_found) { return; }
found.push(row);
output.push(row);


});
}
else {


angular.forEach(collection, function (row) {
var item = row[keyname];
if (item === null || item === undefined) return;
if (keys.indexOf(item) === -1) {
keys.push(item);
output.push(row);
}
});
}


return output;
};
});

更新您的标记:

<select ng-model="orderProp" >
<option ng-repeat="place in places | unique" value="\{\{place.category}}">\{\{place.category}}</option>
</select>

下面是一个简单而通用的示例。

过滤器:

sampleApp.filter('unique', function() {


// Take in the collection and which field
//   should be unique
// We assume an array of objects here
// NOTE: We are skipping any object which
//   contains a duplicated value for that
//   particular key.  Make sure this is what
//   you want!
return function (arr, targetField) {


var values = [],
i,
unique,
l = arr.length,
results = [],
obj;


// Iterate over all objects in the array
// and collect all unique values
for( i = 0; i < arr.length; i++ ) {


obj = arr[i];


// check for uniqueness
unique = true;
for( v = 0; v < values.length; v++ ){
if( obj[targetField] == values[v] ){
unique = false;
}
}


// If this is indeed unique, add its
//   value to our values and push
//   it onto the returned array
if( unique ){
values.push( obj[targetField] );
results.push( obj );
}


}
return results;
};
})

标价:

<div ng-repeat = "item in items | unique:'name'">
\{\{ item.name }}
</div>
<script src="your/filters.js"></script>

更新

我推荐使用 Set,但是对不起,这不适用于 ng-repeat,也不适用于 Map,因为 ng-repeat 只适用于 array。所以忽略这个答案。无论如何,如果你需要过滤掉重复的一种方式是另一种说法使用 angular filters,这里是 链接到开始部分


旧答案

Yo 可以使用 ECMAScript 2015(ES6)标准集合数据结构代替数组,这样在添加到 Set 时可以过滤重复的值。(记住集合不允许重复的值)。非常容易使用:

var mySet = new Set();


mySet.add(1);
mySet.add(5);
mySet.add("some text");
var o = {a: 1, b: 2};
mySet.add(o);


mySet.has(1); // true
mySet.has(3); // false, 3 has not been added to the set
mySet.has(5);              // true
mySet.has(Math.sqrt(25));  // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true


mySet.size; // 4


mySet.delete(5); // removes 5 from the set
mySet.has(5);    // false, 5 has been removed


mySet.size; // 3, we just removed one value

这可能有点过了,但对我很有效。

Array.prototype.contains = function (item, prop) {
var arr = this.valueOf();
if (prop == undefined || prop == null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item) {
return true;
}
}
}
else {
for (var i = 0; i < arr.length; i++) {
if (arr[i][prop] == item) return true;
}
}
return false;
}


Array.prototype.distinct = function (prop) {
var arr = this.valueOf();
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (!ret.contains(arr[i][prop], prop)) {
ret.push(arr[i]);
}
}
arr = [];
arr = ret;
return arr;
}

不同的函数取决于上面定义的包含函数。它可以被称为 array.distinct(prop);,其中道具是您想要区分的属性。

你可以说 $scope.places.distinct("category");

我有一个字符串数组,而不是对象,我使用这种方法:

ng-repeat="name in names | unique"

使用这个过滤器:

angular.module('app').filter('unique', unique);
function unique(){
return function(arry){
Array.prototype.getUnique = function(){
var u = {}, a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
};
if(arry === undefined || arry.length === 0){
return '';
}
else {
return arry.getUnique();
}


};
}

似乎每个人都在把他们自己版本的 unique过滤器扔进环中,所以我也会这样做。非常欢迎批评。

angular.module('myFilters', [])
.filter('unique', function () {
return function (items, attr) {
var seen = {};
return items.filter(function (item) {
return (angular.isUndefined(attr) || !item.hasOwnProperty(attr))
? true
: seen[item[attr]] = !seen[item[attr]];
});
};
});

如果希望基于嵌套键获取唯一数据:

app.filter('unique', function() {
return function(collection, primaryKey, secondaryKey) { //optional secondary key
var output = [],
keys = [];


angular.forEach(collection, function(item) {
var key;
secondaryKey === undefined ? key = item[primaryKey] : key = item[primaryKey][secondaryKey];


if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});


return output;
};
});

这么说吧:

<div ng-repeat="notify in notifications | unique: 'firstlevel':'secondlevel'">

创建您自己的数组。

<select name="cmpPro" ng-model="test3.Product" ng-options="q for q in productArray track by q">
<option value="" >Plans</option>
</select>


productArray =[];
angular.forEach($scope.leadDetail, function(value,key){
var index = $scope.productArray.indexOf(value.Product);
if(index === -1)
{
$scope.productArray.push(value.Product);
}
});

我决定扩展@thethakuri 的回答,以允许这位独特的成员有任何深度。这是密码。这是为那些不想包含整个 AngularUI 模块只是为了这个功能的人准备的。如果你已经在使用 AngularUI,忽略这个答案:

app.filter('unique', function() {
return function(collection, primaryKey) { //no need for secondary key
var output = [],
keys = [];
var splitKeys = primaryKey.split('.'); //split by period




angular.forEach(collection, function(item) {
var key = {};
angular.copy(item, key);
for(var i=0; i<splitKeys.length; i++){
key = key[splitKeys[i]];    //the beauty of loosely typed js :)
}


if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});


return output;
};
});

例子

<div ng-repeat="item in items | unique : 'subitem.subitem.subitem.value'"></div>

这里有一个只有模板的方法来做到这一点(尽管它不维护顺序)。另外,搜索结果也会按顺序排列,这在大多数情况下都很有用:

<select ng-model="orderProp" >
<option ng-repeat="place in places | orderBy:'category' as sortedPlaces" data-ng-if="sortedPlaces[$index-1].category != place.category" value="\{\{place.category}}">
\{\{place.category}}
</option>
</select>

以上的过滤器都没有解决我的问题,所以我不得不从官方 Github 博士。复制过滤器,然后使用它作为解释上述答案

angular.module('yourAppNameHere').filter('unique', function () {

返回函数(条目,过滤器){

if (filterOn === false) {
return items;
}


if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];


var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};


angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;


for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}


});
items = newItems;
}
return items;
};


});