6

I have seen few questions in SO discussing no duplicates allowed in ng-repeat. My question is little different. In my case I am confused because I am not getting the error even if there are duplicate objects in array

Here is my HTML code

<table>
      <tr ng-repeat="item in items">
        <td> {{ item.email}}</td>           
      </tr>
</table>

And here is the code for populating the array

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


$scope.items=[];

  $scope.items.push({
           "id":"1",
           "email":"[email protected]"});
  $scope.items.push({
           "id":"1",
           "email":"[email protected]"});

  $scope.items.push({
           "id":"2",
           "email":"[email protected]"});
  $scope.items.push({
           "id":"2",
           "email":"[email protected]"});


});

As per my understanding I should get the error and there are duplicate objects in array

However its getting rendered perfectly. Here is the plunker link

ng-repeat-demo

Obviously I am missing something basic. Can somebody point out my gap in understanding?

EDIT

Here is what in my application I was facing (only email ids are changed for obvious reason)

ExampleApp.filter("extractEmail", function (){

  return function(items){
    //console.log("test" + input[0].highlight.file[0]);
    var filtered = [];

    console.log(" items == " + items);


    angular.forEach(items, function(item){

      if (item){
        var obj = item.highlight.file[0].toString().match(/([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/);

      if (obj) {
        //console.log(obj[0]);
        filtered.push(obj[0]);
      }

      }


    }); 

    console.log(filtered);
    return filtered;
  }

});

my console.log prints [“[email protected]", “[email protected]", “[email protected]", “[email protected]"]

the error I get

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: x in clusterState| extractEmail, Duplicate key: string:[email protected], Duplicate value: “[email protected]"

I updated the plunker with similar code. Not able to reproduce

Second Edit

The problem was with the version I was using: Angular JS 1.0.x supported duplicates not able to reproduce http://plnkr.co/edit/qrOez7aZ7X1jsOrmkfiP?p=preview

With the later version able to reproduce

http://plnkr.co/edit/q3oPCrW3RepxvWSZ1LB1?p=preview

3
  • 5
    This is one of the few times someone's complaining about not getting an error. Commented May 16, 2015 at 16:11
  • 1
    trying to understand :) Commented May 16, 2015 at 16:28
  • 2
    This is certainly a good thing to try to understand. Angular is concerned about equality, not equivalence. {id: 1} may look like {id: 1}, but ``{id: 1} === {id: 1}` will return false, because it's creating a new Object for each. This is because Objects, and Arrays, are tracked by reference, not by value. Now, if you did var objX = { "id":"1", "email":"[email protected]"}, and then $scope.items.push(objX); $scope.items.push(objX); you'll get the error (because objX === objX is true) Commented May 16, 2015 at 16:54

2 Answers 2

5

Objects in javascript are compared by reference, not by value.
It really doesn't matter if the contents of an object is exactly the same as another one, if the references doesn't points to same object, they are different.
E.g.:

// In this case "var a" and "var b" points to different objects.
var a = {};
var b = {};

a == b; // false

// Here, they points to the same one
var a = {};
var b = a;

a == b; // true

If you need every entry to be distinct you must check every entry yourself.
Angular ngRepeat have a syntax variation that uses track by to let you decide which entry is distinct (or duplicated).

<div ng-repeat="entry for entries track by entry.id">{{entry.email}}</div>
Sign up to request clarification or add additional context in comments.

6 Comments

And that's exactly what "track by" is for in Angular: docs.angularjs.org/api/ng/directive/ngRepeat.
@SkyWriter, you are totally right! track by is the way to go (editing my answer)
docs.angularjs.org/api/ng/directive/ngRepeat "By default, ngRepeat does not allow duplicate items in arrays. This is because when there are duplicates, it is not possible to maintain a one-to-one mapping between collection items and DOM elements." It does not tell anything about references. Dont you think in that case documentation should be more clear
@AbhijitMazumder, if you pass an array like [1, 2, 2, 3] to ngRepeat it will break because the values are passed by copy, thus, 2 are duplicated. When you pass a array of objects the reference is clear (although the presentation isn't) distinct.
@NemoStain see my Update I am trying to reproduce it. Still have pasted the error
|
5

The items are not considered equal because they point to different references.

If you were to track by ID, then you would get an error because the IDs are equal.

<tr ng-repeat="item in items track by item.id">
  <td> {{ item.email}}</td>           
</tr>

See this fiddle: http://jsfiddle.net/aj_r/7d4n9z0u/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.