488

I am defining a custom filter like so:

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

As you can see the ng-repeat where the filter is being used is nested within another ng-repeat

The filter is defined like this:

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

I'm getting:

Error: Duplicates in a repeater are not allowed. Repeater: comment in item.comments | range:1:2 ngRepeatAction@https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/an

Dine
  • 7,223
  • 8
  • 25
  • 35

10 Answers10

973

The solution is actually described here: http://www.anujgakhar.com/2013/06/15/duplicates-in-a-repeater-are-not-allowed-in-angularjs/

AngularJS does not allow duplicates in a ng-repeat directive. This means if you are trying to do the following, you will get an error.

// 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]">

However, changing the above code slightly to define an index to determine uniqueness as below will get it working again.

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

Official docs are here: https://docs.angularjs.org/error/ngRepeat/dupes

pevik
  • 4,523
  • 3
  • 33
  • 44
Ben
  • 60,438
  • 111
  • 314
  • 488
  • 48
    I wanted to mention that you can apply any custom tracking property to define uniqueness, not just $index. Since in this scenario the objects don't have any other properties this works fine. The reason this error happens is that angular is using a dictionary to store the id of an item as the key with the value as the DOM reference. From the code (line 15402 in angular.js) it looks like they are caching previously found DOM elements based on their key as a performance optimization. Since they need unique keys they explicitly throw this error when they find duplicate keys on line 15417 – devshorts Jul 19 '13 at 21:01
  • 16
    `
    ` the "search filter" needs to be before "track by $index"
    – Zhe Hu Feb 14 '14 at 19:55
  • 21
    Yikes, what pointlessly nasty design on Angular's part. It would be very, very easy to miss this issue during development and testing because your array never contained duplicates, only to have your app explode in production when it gets exposed to dupes for the first time. I've built Angular apps before without knowing about the "no dupes" restriction; I now find myself thinking back and wondering whether I unknowingly authored broken code. – Mark Amery Mar 03 '15 at 13:49
  • our app has exploded due to this reason and I am not angular developer, Does `$index` variable exists somewhere ? – Chang Zhao Oct 31 '18 at 08:00
  • note there is a caveat if you update your array elements later it wont re-compile the DOM tags, instead showing stale data. You can use `track by ($index + ':' + row)` so it will update individual ``s whenever its data updated, as well as when a new element is added, without tripping over dupes – Hashbrown Jan 07 '19 at 07:42
  • 1
    if the array items are objects, what makes each unique? – Shlomi Oct 28 '20 at 17:53
  • @Shlomi I'd also like to know the answer to this question. Even when using identical objects (see [this demo](https://stackblitz.com/edit/angularjs-cbgkdi?file=home/home.controller.js)), AngularJS doesn't see them as duplicates. – Jacob Stamm Oct 27 '21 at 15:22
  • @jacob,tbh,idk,i just used track by index to solve it – Shlomi Oct 28 '21 at 20:35
  • 1
    @Shlomi Gotcha. Just beware that `track by $index` has some [big pitfalls](https://stackoverflow.com/a/45723356/4028303). – Jacob Stamm Oct 28 '21 at 21:37
47

For those who expect JSON and still getting the same error, make sure that you parse your data:

$scope.customers = JSON.parse(data)
usefulBee
  • 9,250
  • 10
  • 51
  • 89
  • 5
    this does not work for me, i expect json, after using $http service, but SyntaxError: Unexpected token o at Object.parse (native) – aurelius Mar 18 '15 at 07:35
  • 1
    @Fergus glad this works for you; however, make sure to look for the difference between JSON.parse and JSON.stringify unless you already know. – usefulBee Sep 02 '15 at 14:19
  • 2
    Crazy. After months of working correctly, Angular abruptly decided the JSON returned from a $http() was no longer JSON. Explicitly parsing it solved this problem for us. Thanks for the crazy suggestion. – Eric L. Nov 13 '15 at 19:38
12

I was having an issue in my project where I was using ng-repeat track by $index but the products were not getting reflecting when data comes from database. My code is as below:

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

In the above code, product is a separate directive to display the product.But i came to know that $index causes issue when we pass data out from the scope. So the data losses and DOM can not be updated.

I found the solution by using product.id as a key in ng-repeat like below:

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

But the above code again fails and throws the below error when more than one product comes with same id:

angular.js:11706 Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater

So finally i solved the problem by making dynamic unique key of ng-repeat like below:

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

This solved my problem and hope this will help you in future.

Community
  • 1
  • 1
Mahima Agrawal
  • 1,315
  • 13
  • 13
  • 1
    Surely `track by $index` would be better than `track by (product.id + $index)`? For one thing, `track by $index` is simpler, and for another, you probably don't actually have any guarantee that the values of `(product.id + $index)` will be unique. For instance, if your array starts with a product with `id` of 5 and after that there's a product with `id` of 4, their values of `(product.id + $index)` will both be 5 (5+0 for the first product, 4+1 for the second) and you'll *still* get the *Duplicates in a repeater are not allowed* error. – Mark Amery May 15 '16 at 22:42
  • 1
    I agree with that $ index is simpler but the above solution is worked for me to resolve all the issues i was facing with $index. And in my case product.id is alphanumeric so (product.id + $index) can not be duplicate in any case. So the idea behind this solution was that if $index is causing any issue in a case then we can use any logic with track by which is created id uniquely. – Mahima Agrawal May 17 '16 at 05:32
6

What do you intend your "range" filter to do?

Here's a working sample of what I think you're trying to do: 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
  • 3,877
  • 1
  • 27
  • 28
1

If by chance this error happens when working with SharePoint 2010: Rename your .json file extensions and be sure to update your restService path. No additional "track by $index" was required.

Luckily I was forwarded this link to this rationale:

.json becomes an important file type in SP2010. SP2010 includes certains webservice endpoints. The location of these files is 14hive\isapi folder. The extension of these files are .json. That is the reason it gives such a error.

"cares only that the contents of a json file is json - not its file extension"

Once the file extensions are changed, should be all set.

CR Rollyson
  • 1,521
  • 1
  • 13
  • 12
0

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.

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

Example

<!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>
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Yogesh Sharma
  • 197
  • 1
  • 1
0

Just in case this happens to someone else, I'm documenting this here, I was getting this error because I mistakenly set the ng-model the same as the ng-repeat array:

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

Instead of:

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

I checked the array and didn't have any duplicates, just double check your variables.

Miguel Suarez
  • 192
  • 4
  • 11
0

If you call a ng-repeat within a < ul> tag, you may be able to allow duplicates. See this link for reference. See Todo2.html

Community
  • 1
  • 1
TheUnKnown
  • 681
  • 5
  • 29
-1

My JSON response was like this:

{
    "items":  [
        {
            "index": 1, "name": "Samantha", "rarity": "Scarborough","email": "maureen@sykes.mk"
        },{ 
            "index": 2, "name": "Amanda", "rarity": "Vick", "email": "jessica@livingston.mv"
        }
    ]
}

So, I used ng-repeat = "item in variables.items" to display it.

Jay
  • 1,575
  • 1
  • 17
  • 22
-1

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: sdetail in mydt, Duplicate key: string: , Duplicate value:

I faced this error because i had written wrong database name in my php api part......

So this error may also occurs when you are fetching the data from database base, whose name is written incorrect by you.

lazyCoder
  • 2,544
  • 3
  • 22
  • 41