it-swarm.com.de

Wie ng-repeat doppelte Ergebnisse filtern

Ich führe einen einfachen ng-repeat über eine JSON-Datei aus und möchte Kategorienamen abrufen. Es gibt ungefähr 100 Objekte, die jeweils zu einer Kategorie gehören - es gibt jedoch nur ungefähr 6 Kategorien. 

Mein aktueller Code lautet:

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

Die Ausgabe umfasst 100 verschiedene Optionen, meistens Duplikate. Wie kann ich mit Angular prüfen, ob bereits ein {{place.category}} vorhanden ist, und keine Option erstellen, wenn sie bereits vorhanden ist?

edit: In meinem Javascript $scope.places = JSON data, nur zur Klarstellung

124
JVG

Sie können den unique - Filter von AngularUI (Quellcode hier: AngularUI unique filter ) verwenden und direkt in den ng-options (oder ng-repeat) verwenden.

<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>
137
jpmorin

Oder Sie können mit lodash einen eigenen Filter schreiben.

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

Sie können "unique" (Aliase: uniq) -Filter in angle.filter module.

verwendung: colection | uniq: 'property' 
Sie können auch nach verschachtelten Eigenschaften filtern: colection | uniq: 'property.nested_property'

Was Sie tun können, ist so etwas ..

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: Wir filtern nach Kundennummer, d. H. Doppelte Kunden entfernen

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

Ergebnis
Kundenliste:
foo 10
Takt 20
baz 30

28
a8m

dieser Code funktioniert für mich.

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;
  };
})

und dann

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

Wenn Sie Kategorien auflisten möchten, sollten Sie Ihrer -Intervention in der Ansicht explizit mitteilen.

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

im Controller:

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

Ich beschloss, die Antwort von @ thethakuri zu erweitern, um dem einzigartigen Mitglied jede Tiefe zu ermöglichen. Hier ist der Code. Dies ist für diejenigen, die nicht das gesamte AngularUI-Modul nur für diese Funktionalität verwenden möchten. Wenn Sie AngularUI bereits verwenden, ignorieren Sie diese Antwort:

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;
    };
});

Beispiel

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

Hier ist ein einfaches und allgemeines Beispiel.

Der Filter:

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;
  };
})

Das Markup:

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

AKTUALISIEREN

Ich habe die Verwendung von Set empfohlen, aber leider funktioniert dies nicht für ng-repeat oder Map, da ng-repeat nur mit Array funktioniert. Ignoriere diese Antwort. Wenn Sie jedoch Duplikate herausfiltern müssen, wird angular filters verwendet, wie in der anderen schon erwähnt wurde. Hier ist der Link zum Einstiegsbereich .


Alte Antwort

Sie können den ECMAScript 2015 (ES6) -Standard Set Data Structure verwenden , anstelle einer Array-Datenstruktur filtern Sie auf diese Weise wiederholte Werte, wenn Sie dem Set hinzufügen. (Denken Sie daran, dass Sets keine wiederholten Werte zulassen). Wirklich einfach zu bedienen:

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
2
CommonSenseCode

Ich hatte ein Array von Strings, keine Objekte, und ich habe diesen Ansatz verwendet:

ng-repeat="name in names | unique"

mit diesem Filter:

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(); 
    }

  };
}
1
Helzgate

Wenn Sie eindeutige Daten basierend auf dem verschachtelten Schlüssel erhalten möchten:

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;
        };
    });

Nenne es so:

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

Es scheint, dass jeder seine eigene Version des unique-Filters in den Ring wirft, also mache ich dasselbe. Kritik ist sehr willkommen.

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]];
      });
    };
  });
1
L S

Hier ist nur eine Vorlage, um dies zu tun (die Reihenfolge wird jedoch nicht beibehalten). Außerdem wird das Ergebnis auch bestellt, was in den meisten Fällen nützlich ist:

<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>
1
shoesel

Keiner der obigen Filter hat mein Problem behoben, sodass ich den Filter aus dem offiziellen github doc kopieren musste. Und dann wie in den obigen Antworten beschrieben

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

rückgabefunktion (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;
  };

});
1
Black Mamba

Diesen Filter hinzufügen:

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;
};
});

Aktualisieren Sie Ihr Markup:

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

Das mag übertrieben sein, aber es funktioniert für mich.

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;
}

Die unterschiedliche Funktion hängt von der oben definierten Funktion ab. Es kann als array.distinct(prop); aufgerufen werden, wobei prop die Eigenschaft ist, die Sie unterscheiden möchten.

Du könntest also einfach $scope.places.distinct("category"); sagen 

0
Ikechi Michael

Erstellen Sie Ihr eigenes Array.

<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);
    }
});
0
Akhilesh Kumar