Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Table from 2D array in AngularJS

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.

like image 913
vitaly-t Avatar asked Oct 07 '13 15:10

vitaly-t


1 Answers

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

like image 76
Pete BD Avatar answered Sep 21 '22 23:09

Pete BD