Yinelenen sonuçlardan ng-tekrar filtreleme nasıl yapılır


131

ng-repeatBir JSON dosyası üzerinden basit bir şekilde çalıştırıyorum ve kategori adlarını almak istiyorum. Her biri bir kategoriye ait olan yaklaşık 100 nesne vardır - ancak yalnızca yaklaşık 6 kategori vardır.

Mevcut kodum şu:

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

Çıktı, çoğu kopya olan 100 farklı seçenektir. {{place.category}}Zaten var olup olmadığını kontrol etmek için Angular'ı nasıl kullanırım ve zaten varsa bir seçenek oluşturmam?

düzenleme: Javascript'imde $scope.places = JSON data, sadece açıklığa kavuşturmak için


1
Neden $cope.places'in tekilini çıkarmıyorsun? jquery haritasını kullanın api.jquery.com/map
anazimok

son çalışma çözümünüz neydi? Yukarıda mı yoksa
tekilleştirmeyi

Bunun çözümünü bilmek istiyorum. Lütfen bir takip gönderin. Teşekkürler!
jdstein1

@ jdstein1 Bir TLDR ile başlayacağım: Aşağıdaki yanıtları kullanın veya bir dizideki yalnızca benzersiz değerleri filtrelemek için vanilya Javascript kullanın. Yaptığım şey: Sonunda, mantığım ve MVC anlayışımla ilgili bir sorun oldu. MongoDB'den veri yüklüyordum ve veri dökümü istiyordum ve Angular'ın bu verileri sadece benzersiz yerlere sihirli bir şekilde filtrelemesini istedim. Çözüm, sanki çoğu zaman tembellik yapmayı bırakıp DB modelimi düzeltmekti - benim için bu, Angular'da db.collection.distinct("places")yapmaktan çok çok daha iyi olan Mongo's'u aramaktı! Ne yazık ki bu herkes için işe yaramayacak.
JVG

Güncelleme için teşekkürler!
jdstein1

Yanıtlar:


142

Sen kullanabilirsiniz benzersiz (burada mevcut kaynak kodu: AngularUI Filtreyi AngularUI benzersiz filtre ) ve ng-seçeneklerinde doğrudan kullanmak (veya ng-tekrar).

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

33
Benzersiz AngularUI filtresinin çalışmasını sağlayamayanlar için: filtreler ayrı bir modüldedir: Örneğin, modülünüze ek bir referans olarak eklemelisiniz angular.module('yourModule', ['ui', 'ui.filters']);. AngularUI js dosyasının içine bakana kadar şaşkına döndü.
GFoley83

8
uniqueFiltre şu anda bir parçası olarak bulunabilir angularjs UI Utils
Nick

2
Ui utils'in yeni sürümünde, ui.unique'i kendi başına dahil edebilirsiniz. sadece modül için bower kurulumunu kullanın.
Öğrenim istatistikleri

AngularUI'yi ve bütünlüğünü dahil etmek istemiyor ancak benzersiz filtreyi kullanmak istiyorsanız, unique.js kaynağını uygulamanıza kopyalayıp yapıştırabilir ve ardından angular.module('ui.filters')uygulamanızın adıyla değiştirebilirsiniz .
chakeda

37

Veya lodash kullanarak kendi filtrenizi yazabilirsiniz.

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

Merhaba Mike, gerçekten zarif görünüyor ama benzersiz: durum [alan adım] gibi bir filtreyi geçtiğimde beklendiği gibi çalışmıyor gibi görünüyor, mevcut tüm benzersiz heykellerin istenen listesinin aksine yalnızca ilk sonucu döndürüyor. Herhangi bir tahmin neden?
SinSync

3
Alt çizgi kullansam da, bu çözüm harika çalıştı. Teşekkürler!
Jon Black

Çok zarif çözüm.
JD Smith

1
lodash bir alt çizgi çatalıdır. Daha iyi performansa ve daha fazla yardımcı programa sahiptir.
Mike Ward

2
içinde lodash v4 _.uniqBy(arr, field);iç içe özellikleri için çalışmalıdır
ijavid

30

Angular.filter modülünde 'benzersiz' (takma adlar: uniq) filtre kullanabilirsiniz

kullanım: colection | uniq: 'property'
yuvalanmış özelliklere göre de filtreleyebilirsiniz: colection | uniq: 'property.nested_property'

Yapabileceğin şey, bunun gibi bir şey ..

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: Müşteri kimliğine göre filtreliyoruz, yani mükerrer müşterileri kaldırıyoruz

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

sonuç
Müşteri listesi:
foo 10
bar 20
baz 30


cevabınız gibi, ama benim sorunuma tercüme etmekte zorlanıyorum. İç içe geçmiş bir listeyle nasıl başa çıkarsınız? Örneğin, her sipariş için bir öğe listesi içeren bir sipariş listesi. Örneğinizde, sipariş başına bir müşteriniz var. Tüm siparişlerde benzersiz bir ürün listesi görmek istiyorum. Konuya değinmek istemem ama, bunu bir müşterinin birçok siparişi olduğu ve bir siparişin birçok ürünü olduğu için de düşünebilirsiniz. Bir müşterinin sipariş ettiği önceki tüm ürünleri nasıl gösterebilirim? Düşünceler?
Greg Grater

@GregGrater Probleminize benzer bir örnek nesne sağlayabilir misiniz?
a8m

Teşekkürler @Ariel M.! İşte verilere bir örnek:
Greg Grater

Hangi açısal versiyonlarla uyumludur?
Icet

15

bu kod benim için çalışıyor.

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

ve sonra

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

2
L'nin tanımı l = dizi! = Tanımsız olmalıdır? arr.length: 0 aksi halde angularjs'de bir ayrıştırma hatası var
Gerrit

6

Kategorileri listelemek istiyorsanız, görünümde niyetinizi açıkça belirtmeniz gerektiğini düşünüyorum.

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

kontrolörde:

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

bunu biraz daha açıklar mısın? Her benzersiz kategori için bu öğeleri arka arkaya tekrarlamak istiyorum. JS, denetleyicinin tanımlandığı JS dosyasına mı giriyor?
mark1234

Seçenekleri gruplamak istiyorsanız, bu farklı bir sorudur. Optgroup öğesine bakmak isteyebilirsiniz. Açısal, optgroup destekler. yönergede group byifade arayın select.
Tosh

Bir yer eklenmesi / kaldırılması durumunda olacak mı? İlgili kategori yerlerdeki tek örnekse eklenecek / kaldırılacak mı?
Greg Grater

4

İşte basit ve genel bir örnek.

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

İşaretleme:

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

Bu iyi çalışıyor ancak konsolda Cannot read property 'length' of undefinedsatırda bir hata atıyorl = arr.length
Soul Eeater

4

Eşsiz üye için herhangi bir derinliğe izin vermek için @ thethakuri'nin cevabını genişletmeye karar verdim. İşte kod. Bu, sadece bu işlevsellik için tüm AngularUI modülünü dahil etmek istemeyenler içindir. Zaten AngularUI kullanıyorsanız, bu yanıtı göz ardı edin:

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

Misal

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

2

Nesneler değil, dizelerim vardı ve bu yaklaşımı kullandım:

ng-repeat="name in names | unique"

bu filtre ile:

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

  };
}

2

GÜNCELLEME

Set'in kullanılmasını tavsiye ediyordum ama üzgünüm bu ng-yinelemede veya Map'de çalışmıyor çünkü ng-yineleme yalnızca dizi ile çalışıyor. Bu yüzden bu cevabı görmezden gelin. her neyse, yinelenenleri filtrelemeniz gerekiyorsa, bir yol diğerinin de söylediği gibi angular filters, işte bunun için başlangıç ​​bölümüne bağlantı .


Eski cevap

Yo kullanabilirsiniz ECMAScript 2015 (ES6) standart Seti Veri yapısını Kümenize eklerken tekrarlanan değerleri filtrelemek bu şekilde yapılandırın yerine Array Veriler,. (Kümelerin tekrarlanan değerlere izin vermediğini unutmayın). Kullanımı gerçekten çok kolay:

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

İşte bunu yapmanın yalnızca şablonlu bir yolu (yine de sırayı korumuyor). Ayrıca, sonuç da sıralanacaktır ve bu çoğu durumda yararlıdır:

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

2

Yukarıdaki filtrelerden hiçbiri sorunumu çözmedi , bu yüzden filtreyi resmi github belgesinden kopyalamak zorunda kaldım . Ve sonra yukarıdaki cevaplarda açıklandığı gibi kullanın

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

dönüş işlevi (öğeler, 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

Görünüşe göre herkes kendi uniquefiltre versiyonunu ringe atıyor, ben de aynısını yapacağım. Eleştiri çok hoş karşılanır.

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

İç içe geçmiş anahtara göre benzersiz veriler almak istiyorsanız:

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

Şöyle diyelim:

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

0

Bu filtreyi ekleyin:

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

İşaretlemenizi güncelleyin:

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

0

Bu aşırı olabilir ama benim için işe yarıyor.

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

Farklı işlev, yukarıda tanımlanan içeren işlevine bağlıdır. array.distinct(prop);Burada prop, farklı olmasını istediğiniz özellik olarak adlandırılabilir .

Yani sadece söyleyebilirsin $scope.places.distinct("category");


0

Kendi dizinizi oluşturun.

<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);
    }
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.