J'exécute un simple ng-repeat
sur un fichier JSON et je veux obtenir les noms de catégorie. Il y a environ 100 objets, chacun appartenant à une catégorie - mais il n'y a qu'environ 6 catégories.
Mon code actuel est le suivant:
<select ng-model="orderProp" >
<option ng-repeat="place in places" value="{{place.category}}">{{place.category}}</option>
</select>
La sortie contient 100 options différentes, principalement des doublons. Comment utiliser Angular pour vérifier si un {{place.category}}
existe déjà et ne pas créer une option s'il y en a déjà une?
edit: Dans mon javascript, $scope.places = JSON data
, juste pour clarifier
Vous pouvez utiliser le filtre unique de AngularUI (code source disponible ici: AngularUI unique filter ) et l’utiliser directement dans ng-options (ou 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>
Ou vous pouvez écrire votre propre filtre en utilisant lodash.
app.filter('unique', function() {
return function (arr, field) {
return _.uniq(arr, function(a) { return a[field]; });
};
});
Vous pouvez utiliser le filtre 'unique' (aliases: uniq) dans angular.filter module
utilisation: colection | uniq: 'property'
vous pouvez également filtrer par propriétés imbriquées: colection | uniq: 'property.nested_property'
Qu'est-ce que vous pouvez faire, c'est quelque chose comme ça ..
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: Nous filtrons par ID client, c'est-à-dire supprimons les clients en double.
<th>Customer list: </th>
<tr ng-repeat="order in orders | unique: 'customer.id'" >
<td> {{ order.customer.name }} , {{ order.customer.id }} </td>
</tr>
résultat
Liste de clients:
foo 10
bar 20
baz 30
ce code fonctionne pour moi.
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;
};
})
et alors
var colors=$filter('unique')(items,"color");
Si vous souhaitez lister les catégories, je pense que vous devriez indiquer explicitement votre intention Dans la vue.
<select ng-model="orderProp" >
<option ng-repeat="category in categories"
value="{{category}}">
{{category}}
</option>
</select>
dans le contrôleur:
$scope.categories = $scope.places.reduce(function(sum, place) {
if (sum.indexOf( place.category ) < 0) sum.Push( place.category );
return sum;
}, []);
J'ai décidé d'étendre la réponse de @ thethakuri pour permettre une profondeur au membre unique. Voici le code. Ceci est destiné à ceux qui ne souhaitent pas inclure le module AngularUI complet uniquement pour cette fonctionnalité. Si vous utilisez déjà AngularUI, ignorez cette réponse:
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;
};
});
Exemple
<div ng-repeat="item in items | unique : 'subitem.subitem.subitem.value'"></div>
Voici un exemple simple et générique.
Le filtre:
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;
};
})
Le balisage:
<div ng-repeat = "item in items | unique:'name'">
{{ item.name }}
</div>
<script src="your/filters.js"></script>
Je recommandais l'utilisation de Set mais je regrette que cela ne fonctionne pas pour ng-repeat, ni Map car ng-repeat ne fonctionne qu'avec array. Alors ignorez cette réponse. Quoi qu'il en soit, si vous avez besoin de filtrer les doublons d'une manière, comme d'autres l'ont déjà dit, utilisez angular filters
, voici le lien correspondant à la section pour commencer .
Vous pouvez également utiliser la structure de données Set standard - ECMAScript 2015 (ES6) , au lieu d’une structure de données de tableau de cette façon, vous filtrez les valeurs répétées lors de l’ajout au jeu. (Rappelez-vous que les ensembles n'autorisent pas les valeurs répétées). Vraiment facile à utiliser:
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
J'ai eu un tableau de chaînes, pas d'objets et j'ai utilisé cette approche:
ng-repeat="name in names | unique"
avec ce filtre:
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();
}
};
}
Si vous souhaitez obtenir des données uniques basées sur la clé imbriquée:
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;
};
});
Appelez ça comme ça:
<div ng-repeat="notify in notifications | unique: 'firstlevel':'secondlevel'">
Il semble que tout le monde jette sa propre version du filtre unique
dans l'anneau, je vais donc en faire autant La critique est la bienvenue.
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]];
});
};
});
Voici un moyen de le faire uniquement sur un modèle (il ne s'agit toutefois pas de maintenir l'ordre). De plus, le résultat sera commandé, ce qui est utile dans la plupart des cas:
<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>
Aucun des filtres ci-dessus n'a résolu mon problème et j'ai donc dû copier le filtre à partir du document officiel github. Et ensuite utilisez-le comme expliqué dans les réponses ci-dessus
angular.module('yourAppNameHere').filter('unique', function () {
fonction de retour (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;
};
});
Ajouter ce filtre:
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;
};
});
Mettez à jour votre balisage:
<select ng-model="orderProp" >
<option ng-repeat="place in places | unique" value="{{place.category}}">{{place.category}}</option>
</select>
C'est peut-être exagéré, mais cela fonctionne pour moi.
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;
}
La fonction distincte dépend de la fonction contient définie ci-dessus. On peut l'appeler array.distinct(prop);
où prop est la propriété que vous voulez différencier.
Donc, vous pouvez simplement dire $scope.places.distinct("category");
Créez votre propre tableau.
<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);
}
});