Как сделать ng-repeat отфильтровать повторяющиеся результаты
Я простой ng-repeat над файлом JSON и хотите получить имена категорий. Есть около 100 объектов, каждый из которых принадлежит к категории-но есть только около 6 категорий.
мой текущий код такой:
<select ng-model="orderProp" >
<option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>
выход 100 различных вариантов, в основном дубликатов. Как использовать Angular, чтобы проверить, является ли a {{place.category}} уже существует, а не создать опцию, если она уже есть?
edit: в моем javascript,$scope.places = JSON data, просто разъяснить
16 ответов:
вы могли бы использовать уникальный фильтр от 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>
или вы можете написать свой собственный фильтр с помощью lodash.
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: мы фильтруем по идентификатору клиента, т. е. удаляем дубликаты клиентов
<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
баз 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");
Если вы хотите перечислить категории, я думаю, что вы должны явно указать свой намерение в представлении.
<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; }, []);
вот простой и общий пример.
фильтр:
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>
Я решил расширить ответ @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>
обновление
я рекомендовал использовать Set, но жаль, что это не работает для ng-repeat, ни Map, так как ng-repeat работает только с массивом. Так что игнорируйте этот ответ. в любом случае, если вам нужно отфильтровать дубликаты одним способом, как сказал другой, используя
angular filters, вот ссылка на него в разделе начало работы.
ответ
вы можете использовать структура данных стандартного набора ECMAScript 2015 (ES6) вместо массива Структура данных таким образом вы фильтруете повторяющиеся значения при добавлении в набор. (Помните, что наборы не позволяют повторять значения). Очень проста в использовании:
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
у меня есть массив строк, а не объектов, и я использовал такой подход:
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); } });
вот шаблон-единственный способ сделать это (это не поддержание порядка, хотя). Кроме того, результат также будет упорядочен, что полезно в большинстве случаев:
<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>
ни один из вышеперечисленных фильтров не исправил мою проблему, поэтому мне пришлось скопировать фильтр из official гитхаб док. а затем использовать его, как описано в приведенных выше ответах
angular.module('yourAppNameHere').filter('unique', function () {функция возврата (items, filterOn) {
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; }; });
добавить такой фильтр:
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>
Это может быть перебор, но это работает для меня.
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; }функция distinct зависит от функции contains, определенной выше. Его можно назвать как
array.distinct(prop);где prop-это свойство, которое вы хотите отличить.Так что вы могли бы просто сказать
$scope.places.distinct("category");
Comments