6

I'm stuck on something that I was expecting with AngularJS to work out of the box without any issues, and yet strangely enough...

I'm using a JSON service that returns data as a 2D array:

$scope.data= [
    ["val-11", "val-12", "val-13"],
    ["val-21", "val-22", "val-23"]
    ];

From this I'm trying to generate a table like this:

<table>
<tr ng-repeat="row in data">
<td ng-repeat="col in row">{{col}}</td>
</tr>
</table>

I don't understand why AngularJS doesn't handle such a basic scenario. I can get correct $index for the parent loop, if I need it, I can iterate through the values, but only with one loop like this "col in data[0]", but I cannot get any result trying to use the nested loop as shown above.

Am I doing something wrong? It just seems to be too basic not to work right away. Please somebody help me with this bizarre issue.

4
  • working fine for me: jsfiddle.net/AWkQj Commented Oct 7, 2013 at 15:46
  • I found the problem (see below), it is just a plain bug. Too bad somebody down-voted my question, it is a serious issue for AngularJS team to resolve. Commented Oct 7, 2013 at 16:26
  • You should see an error in your console with a link to docs.angularjs.org/error/ngRepeat:dupes Commented Oct 7, 2013 at 17:03
  • Yes, the following syntax seems to work with 1.2 RC2: <table> <tr ng-repeat="row in data"> <td ng-repeat="col in row track by $index"> {{col}} </td> </tr> </table>. But it doesn't work in earlier released versions, which means it is a breaking feature. Thank you for pointing this out. I did like the way it worked in earlier versions though, because this is what anyone would expect it to work. Commented Oct 7, 2013 at 19:15

1 Answer 1

14

In Angular 1.0.x the ng-repeat directive had numerous bugs caused by trying to "guess" whether non-object values (i.e. strings or numbers) had been added, removed or moved. The problem is that non-objects have no identity of their own, so it is impossible to track them accurately. This was problematic in a number of cases and also caused the ngRepeat code to be bloated with loads of workarounds and edge cases.

In 1.2 we improved the syntax for ng-repeat to allow the developer to specify for themselves exactly how to identify items in a collection. This is done by the "track by" keyword. One consequence of this is that we disallow items which have the same identifier.

By default ng-repeat will try to track by the value of the item. If you have repeated items such as the same object or identical strings or numbers then ng-repeat will complain and you will see the error in the console.

var TableCtrl = function($scope) {
  $scope.data= [
    ["", "", "val-13"]
  ];
}

Here the first two items in the sub-array are the same "empty" string. See this fiddle: http://jsfiddle.net/tEU8r/

If you really do want to have repeated items in the collection then you need to provide a method for ng-repeat to distinguish them. The simplest and obvious approach is to track the items by their position in the collection. This is done by using "track by $index". Here is the same example but fixed in this way:

<table ng-controller="TableCtrl">
  <tr ng-repeat="row in data">
    <td ng-repeat="col in row track by $index">
       {{$parent.$index}}-{{$index}} {{col}}
    </td>
  </tr>
</table>

http://jsfiddle.net/h44Z8/

So this is not a bug in AngularJS. But you are correct that people should be aware of this change when upgrading to 1.2

Sign up to request clarification or add additional context in comments.

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.