Erreur angulaire de répétition ng «Les doublons dans un répéteur ne sont pas autorisés.»

472

Je définis un filtre personnalisé comme ceci:

<div class="idea item" ng-repeat="item in items" isoatom>    
    <div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
        ....
    </div>
</div>

Comme vous pouvez le voir, le ng-repeat où le filtre est utilisé est imbriqué dans un autre ng-repeat

Le filtre est défini comme ceci:

myapp.filter('range', function() {
    return function(input, min, max) {
        min = parseInt(min); //Make string input int
        max = parseInt(max);
        for (var i=min; i<max; i++)
            input.push(i);
        return input;
    };
});

Je suis en train:

Erreur: les doublons dans un répéteur ne sont pas autorisés. Répéteur: commentaire dans item.comments | plage: 1: 2 ngRepeatAction @ https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/an

Dîner
la source

Réponses:

954

La solution est en fait décrite ici: http://www.anujgakhar.com/2013/06/15/duplicates-in-a-repeater-are-not-allowed-in-angularjs/

AngularJS n'autorise pas les doublons dans une directive ng-repeat. Cela signifie que si vous essayez de faire ce qui suit, vous obtiendrez une erreur.

// This code throws the error "Duplicates in a repeater are not allowed.
// Repeater: row in [1,1,1] key: number:1"
<div ng-repeat="row in [1,1,1]">

Cependant, changer légèrement le code ci-dessus pour définir un index pour déterminer l'unicité comme ci-dessous le fera fonctionner à nouveau.

// This will work
<div ng-repeat="row in [1,1,1] track by $index">

Les documents officiels sont ici: https://docs.angularjs.org/error/ngRepeat/dupes

Webnet
la source
48
Je voulais mentionner que vous pouvez appliquer n'importe quelle propriété de suivi personnalisée pour définir l'unicité, pas seulement $ index. Étant donné que dans ce scénario, les objets n'ont pas d'autres propriétés, cela fonctionne très bien. La raison pour laquelle cette erreur se produit est que angular utilise un dictionnaire pour stocker l'id d'un élément comme clé avec la valeur comme référence DOM. D'après le code (ligne 15402 dans angular.js), il semble qu'ils mettent en cache les éléments DOM trouvés précédemment en fonction de leur clé comme optimisation des performances. Puisqu'ils ont besoin de clés uniques, ils lancent explicitement cette erreur lorsqu'ils trouvent des clés en double sur la ligne 15417
devshorts
16
<div ng-repeat="row in [1,1,1,2,2] |filter: 2 track by $index" >le "filtre de recherche" doit être avant "suivre par $ index"
Zhe Hu
21
Yikes, quel design inutilement méchant de la part d'Angular. Il serait très, très facile de passer à côté de ce problème lors du développement et des tests car votre baie ne contenait jamais de doublons, seulement pour que votre application explose en production lorsqu'elle est exposée à des dupes pour la première fois. J'ai déjà créé des applications Angular sans connaître la restriction "pas de dupes"; Je me retrouve maintenant à réfléchir et à me demander si j'ai sans le savoir créé du code cassé.
Mark Amery
notre application a explosé pour cette raison et je ne suis pas développeur angulaire, la $indexvariable existe- t-elle quelque part?
Chang Zhao
notez qu'il y a une mise en garde si vous mettez à jour vos éléments de tableau plus tard, il ne recompilera pas les balises DOM, au lieu d'afficher les données périmées. Vous pouvez l'utiliser track by ($index + ':' + row)pour mettre à jour chaque individu <ng-repeat>chaque fois que ses données sont mises à jour, ainsi que lorsqu'un nouvel élément est ajouté, sans trébucher sur les dupes
Hashbrown
45

Pour ceux qui attendent JSON et obtiennent toujours la même erreur, assurez-vous d'analyser vos données:

$scope.customers = JSON.parse(data)
utileBee
la source
4
cela ne fonctionne pas pour moi, j'attends json, après avoir utilisé le service $ http, mais SyntaxError: Jeton inattendu o à Object.parse (natif)
aurelius
1
@Fergus heureux que cela fonctionne pour vous; cependant, assurez-vous de rechercher la différence entre JSON.parse et JSON.stringify à moins que vous ne le sachiez déjà.
utileBee
2
Fou. Après des mois de travail correct, Angular a brusquement décidé que le JSON revenu d'un $ http () n'était plus du JSON. L'analyse explicite a résolu ce problème pour nous. Merci pour la folle suggestion.
Eric L.
12

J'avais un problème dans mon projet où j'utilisais ng-repeat track par $ index mais les produits ne reflétaient pas lorsque les données provenaient de la base de données. Mon code est comme ci-dessous:

<div ng-repeat="product in productList.productList track by $index">
  <product info="product"></product>
 </div>

Dans le code ci-dessus, le produit est une directive distincte pour afficher le produit, mais j'ai appris que $ index provoque un problème lorsque nous transmettons des données de la portée. Les pertes de données et DOM ne peuvent donc pas être mis à jour.

J'ai trouvé la solution en utilisant product.id comme clé dans ng-repeat comme ci-dessous:

<div ng-repeat="product in productList.productList track by product.id">
  <product info="product"></product>
 </div>

Mais le code ci-dessus échoue à nouveau et génère l'erreur ci-dessous lorsque plusieurs produits sont livrés avec le même identifiant:

angular.js: 11706 Erreur: [ngRepeat: dupes] Les doublons dans un répéteur ne sont pas autorisés. Utilisez l'expression «track by» pour spécifier des clés uniques. Répétiteur

J'ai finalement résolu le problème en créant une clé unique dynamique de ng-repeat comme ci-dessous:

<div ng-repeat="product in productList.productList track by (product.id + $index)">
  <product info="product"></product>
 </div>

Cela a résolu mon problème et j'espère que cela vous aidera à l'avenir.

Mahima Agrawal
la source
1
Ce track by $indexserait sûrement mieux que track by (product.id + $index)? D'une part, track by $indexc'est plus simple, et d'autre part, vous n'avez probablement aucune garantie que les valeurs de (product.id + $index)seront uniques. Par exemple, si votre tableau commence par un produit avec id5 et ensuite il y a un produit avec id4, leurs valeurs de (product.id + $index)seront toutes deux 5 (5 + 0 pour le premier produit, 4 + 1 pour le second) et vous obtenir toujours les doublons dans un répéteur ne sont pas autorisés à l' erreur.
Mark Amery
1
Je suis d'accord avec le fait que $ index est plus simple mais la solution ci-dessus est travaillée pour moi afin de résoudre tous les problèmes auxquels j'étais confronté avec $ index. Et dans mon cas, product.id est alphanumérique, donc (product.id + $ index) ne peut en aucun cas être dupliqué. Donc, l'idée derrière cette solution était que si $ index provoque un problème dans un cas, nous pouvons utiliser n'importe quelle logique avec une piste par laquelle est créé id de manière unique.
Mahima Agrawal
5

Que comptez-vous faire avec votre filtre "gamme"?

Voici un échantillon de travail de ce que je pense que vous essayez de faire: http://jsfiddle.net/evictor/hz4Ep/

HTML:

<div ng-app="manyminds" ng-controller="MainCtrl">
  <div class="idea item" ng-repeat="item in items" isoatom>    
    Item {{$index}}
    <div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
      Comment {{$index}}
      {{comment}}
    </div>
  </div>
</div>

JS:

angular.module('manyminds', [], function() {}).filter('range', function() {
    return function(input, min, max) {
        var range = [];
        min = parseInt(min); //Make string input int
        max = parseInt(max);
        for (var i=min; i<=max; i++)
            input[i] && range.push(input[i]);
        return range;
    };
});

function MainCtrl($scope)
{
    $scope.items = [
        {
            comments: [
                'comment 0 in item 0',
                'comment 1 in item 0'
            ]
        },
        {
            comments: [
                'comment 0 in item 1',
                'comment 1 in item 1',
                'comment 2 in item 1',
                'comment 3 in item 1'
            ]
        }
    ];
}
Ezekiel Victor
la source
1

Si, par hasard, cette erreur se produit lorsque vous travaillez avec SharePoint 2010: renommez vos extensions de fichier .json et assurez-vous de mettre à jour votre chemin restService. Aucun "suivi par $ index" supplémentaire n'était requis.

Heureusement, on m'a transmis ce lien vers cette justification:

.json devient un type de fichier important dans SP2010. SP2010 inclut certains points de terminaison de service Web. L'emplacement de ces fichiers est le dossier 14hive \ isapi. L'extension de ces fichiers est .json. C'est la raison pour laquelle il donne une telle erreur.

"se soucie seulement que le contenu d'un fichier json est json - pas son extension de fichier"

Une fois que les extensions de fichier sont modifiées, elles devraient être toutes définies.

CR Rollyson
la source
0

Juste au cas où cela arriverait à quelqu'un d'autre, je documente cela ici, j'obtenais cette erreur parce que j'ai par erreur défini le modèle ng de la même manière que le tableau ng-repeat:

 <select ng-model="list_views">
     <option ng-selected="{{view == config.list_view}}"
         ng-repeat="view in list_views"
         value="{{view}}">
         {{view}}
     </option>
 </select>

Au lieu de:

<select ng-model="config.list_view">
     <option ng-selected="{{view == config.list_view}}"
         ng-repeat="view in list_views"
         value="{{view}}">
         {{view}}
     </option>
 </select>

J'ai vérifié le tableau et je n'ai pas eu de doublons, vérifiez simplement vos variables.

Miguel Suarez
la source
0

Les doublons dans un répéteur ne sont pas autorisés. Utilisez l'expression «track by» pour spécifier des clés uniques.

Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}

Exemple

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="angular.js"></script>

</head>
<body>
    <div ng-app="myApp" ng-controller="personController">
        <table>
            <tr> <th>First Name</th> <th>Last Name</th> </tr>
            <tr ng-repeat="person in people track by $index">
                <td>{{person.firstName}}</td>
                <td>{{person.lastName}}</td>
                <td><input type="button" value="Select" ng-click="showDetails($index)" /></td>
            </tr>

        </table> <hr />
        <table>
            <tr ng-repeat="person1 in items track by $index">
                <td>{{person1.firstName}}</td>
                <td>{{person1.lastName}}</td>
            </tr>
        </table>
        <span>   {{sayHello()}}</span>
    </div>
    <script> var myApp = angular.module("myApp", []);
        myApp.controller("personController", ['$scope', function ($scope)
        { 
            $scope.people = [{ firstName: "F1", lastName: "L1" },
                { firstName: "F2", lastName: "L2" }, 
                { firstName: "F3", lastName: "L3" }, 
                { firstName: "F4", lastName: "L4" }, 
                { firstName: "F5", lastName: "L5" }]
            $scope.items = [];
            $scope.selectedPerson = $scope.people[0];
            $scope.showDetails = function (ind) 
            { 
                $scope.selectedPerson = $scope.people[ind];
                $scope.items.push($scope.selectedPerson);
            }
            $scope.sayHello = function ()
            {
                return $scope.items.firstName;
            }
        }]) </script>
</body>
</html>
Yogesh Sharma
la source
2
Veuillez déclarer toute affiliation à tous les liens que vous publiez
Draken
0

Si vous appelez une répétition ng dans une balise <ul>, vous pourrez peut-être autoriser les doublons. Voir ce lien pour référence. Voir Todo2.html

L'inconnu
la source
-1

Ma JSONréponse était comme ceci:

{"items": 
  &nbsp;[
    &nbsp;&nbsp;{
      "index": 1,
      "name": "Samantha",
      "rarity": "Scarborough",
      "email": "[email protected]"
    },
    &nbsp;&nbsp;{
      "index": 2,
      "name": "Amanda",
      "rarity": "Vick",
      "email": "[email protected]"
    }]
}

J'ai donc l'habitude ng-repeat = "item in variables.items" de l'afficher.

Geai
la source
-1

Les doublons dans un répéteur ne sont pas autorisés. Utilisez l'expression «track by» pour spécifier des clés uniques. Répéteur: sdetail dans mydt, Clé en double: chaîne:, Valeur en double:

J'ai rencontré cette erreur parce que j'avais écrit un nom de base de données incorrect dans ma partie api php ......

Cette erreur peut donc également se produire lorsque vous récupérez les données de la base de données, dont le nom est incorrect écrit par vous.

Vishal Solanki
la source