web-dev-qa-db-fra.com

AngularJs Supprimer les éléments en double dans ng-repeat

J'ai un dictionnaire stocké dans field_detail

<li ng-repeat = "field in field_detail">{{field.displayName}}</li>

Maintenant, je ne veux pas inclure les doublons displayName de field_detail, que filter dois-je utiliser?

36
Pawan

Créez simplement un filtre qui obtient les valeurs uniques, probablement par une clé. Quelque chose comme ça devrait faire (je n'ai pas testé cela du tout, donc je vous laisse cette affaire, c'est juste pour vous donner une idée):

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

      angular.forEach(collection, function(item) {
          var key = item[keyname];
          if(keys.indexOf(key) === -1) {
              keys.Push(key);
              output.Push(item);
          }
      });

      return output;
   };
});
<div ng-repeat="item in items | unique: 'id'"></div>

Remarque: Array.indexOf () ne fonctionne pas dans IE8, donc si vous prenez en charge IE8, vous devrez stub dans indexOf (), ou vous devrez utiliser une approche légèrement différente .

Autres réflexions: il est probablement préférable de simplement créer un filtre qui exploite la fonction unique en lowdash ou underscore si vous faites déjà référence à ces bibliothèques.

78
Ben Lesh

J'ai travaillé sur un JSFiddle basé sur la réponse fournie par Ben Leash:

http://jsfiddle.net/ThunderHemlock/bvsvzrr5/1/

Merci, Ben. D'autres réponses nécessitaient l'utilisation de AngularJS UI ou d'autres frameworks supplémentaires.

var app = angular.module('app', []);

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

      angular.forEach(collection, function(item) {
          var key = item[keyname];
          if(keys.indexOf(key) === -1) {
              keys.Push(key);
              output.Push(item);
          }
      });
      return output;
   };
});

app.controller('MyCtrl', function ($scope) {

$scope.items = [
      {
        id : 1,
        column : "col1",
        comment : "col1-label1",
        text1 : "col1-label1-text1",
        checked: false,

      },
      {
        id : 2,
        column : "col1",
        comment : "col1-label2",
        text1 : "col1-label2-text1",
        checked: false,

      },
      {
        id : 3,
        column : "col2",
        comment : "col2-label1",
        text1 : "col2-label1-text1",
        checked: false,

      },
      {
        id : 4,
        column : "col2",
        comment : "col2-label2",
        text1 : "col2-label2-text1",
        checked: false,

      },
      {
        id : 5,
        column : "col3",
        comment : "col3-label1",
        text1 : "col3-label1-text1",
        checked: false,

      },
      {
        id : 6,
        column : "col3",
        comment : "col3-label2",
        text1 : "col3-label2-text1",
        checked: false,

      },
      {
        id : 7,
        column : "col4",
        comment : "col4-label1",
        text1 : "col4-label1-text1",
        checked: false,

      },
      {
        id : 8,
        column : "col4",
        comment : "col4-label2",
        text1 : "col4-label2-text1",
        checked: false,

      }
      ];
    });



<div ng-app="app">
        <div ng-controller="MyCtrl as item">
            <ul>
                <li ng-repeat="item in items | unique: 'column'">
                    {{ item.column }}
                </li>
            </ul>
        </div>
    </div>
14
Thunder Hemlock

Pour se superposer à Ben Lesh, j'ai ajouté l'option pour supprimer les objets en double dans un tableau si le nom de clé est faux:

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;
};
});
3
Shawn Dotey

Je reçois un ticket indiquant que lorsque l'utilisateur clique sur Enregistrer, il obtient une erreur indiquant une violation de contrainte unique, bla bla .. Il souhaite que mon écran affiche les doublons avant que la base de données n'applique la contrainte. J'ai donc écrit une fonction pour parcourir toutes les instances du tableau d'objets et en compter les instances.

$scope.anyDuplicates = function () {
    var dupes = false;
    for (var i = 0; i < $scope.kpiList.length; i++) {
        $scope.kpiList[i].cnt = 0;

        for (var j = 0; j < $scope.kpiList.length; j++) {

            if ($scope.kpiList[i].description == $scope.kpiList[j].description) {
                $scope.kpiList[i].cnt++;
            }

            if ($scope.kpiList[i].cnt > 1) dupes = true;
        }
    }
    return dupes;
}

... et j'utilise cette fonction dans mon script pour empêcher la sauvegarde, comme ceci:

if ($scope.anyDuplicates()) { 
   alert('Duplicates Detected.  Please remove the duplicates before pressing the save button.'); 
} else { 
   save();
}

... et pour montrer à l'utilisateur dès qu'il ajoute un nouvel enregistrement, comme ceci:

$scope.kpiList.Push({kpiId: newId, description: newDescription, new: true});
$scope.anyDuplicates();

... et puis dans mon HTML j'ai quelque chose à dire à l'utilisateur où se trouve le doublon ...

<tr ng-repeat="row in kpiList | filter:searchText | orderBy:['kpiTypeId', 'description'] ">
<td>
   <span 
      ng-show="row.cnt > 1" 
      style="color: red; font-size: xx-small">
      duplicate
   </span>
</td>
...
</tr>

Oui, je compare intentionnellement chaque instance à elle-même. Il y a moins de code de cette façon. Je vérifie si .cnt> 1 au lieu de> 0.

Aussi pour prendre note de ... le champ kpiList.cnt n'existe que lorsque la fonction s'exécute pour la première fois. Le ng-show = "row.cnt> 1" indiquera un faux (pas vrai) et ne s'affichera pas jusqu'à ce que row.cnt ait une valeur.

En outre, vous devez utiliser une feuille de style pour formater votre étendue au lieu de la placer dans l'attribut style.

2
D. Kermott

Créez votre propre fonction:

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

});

1
Akhilesh Kumar