D Joyal D Joyal - 1 month ago 20
AngularJS Question

AngularJS ng-repeat dictionary with array value

I've run into trouble creating an HTML table from an indeterminate JSON object using the AngularJS ng-repeat. What I want to accomplish is to feed in a JSON object with the general format:

{
"My First Key" : [0, 1, 2 ..., n],
"My Second Key" : ["Val0", "Val1", ..., "Valn"],
...
"My Nth Key" : [0, 1, 2 ..., n]
}


And be able to create a table with the format:

My First Key | My Second Key | ... | My Nth Key |
0 | "Val0" | ... | 0 |
1 | "Val1" | ... | 1 |
... | ... | ... | ... |
n | "Valn" | ... | n |


All values in the dictionary are arrays of equal length. The keys (IE: the actual value of "My First Key, My Second Key") are unknown as well. The contents of the array are either strings or numbers. There is no mixing of data types within each array. It's also important to note that I won't actually know what the string corresponding to each key is when the expression evaluates.

Using the ng-repeat="(key, value) in myArray" (where myArray is the above data structure in some controller) can successfully build the header of the table:

<table ng-controller="myController">
<tr>
<th ng-repeat="(key, value) in myArray">{{key}}</th>
</tr>
<tr ng-repeat="???">
<td>{{data}}</td>
</tr>
</table>


Is this possible with my given data structure and limitations? If so, how do I access the array values inside of value in an ng-repeat?
A point of note, I was able to create a janky version of the desired result by displaying several single-column tables alongside one another (see this JSFiddle). However I'm looking for a more elegant solution (my janky version also starts to fall apart as soon as there are too many columns to fit on a single line).

Answer

You can do this by choosing one of your columns as a guide, and iterate over them to walk on each row producing an $index. So then, you can iterate the columns again using the row guide (aka $parent.$index) created previously.

Observations: If your choosen column doesn't fit the proper number of rows, it will make the other columns to stop at the same mark, so if your guide column has less rows than the others, it will render just this number of rows. So, make sure that all columns have the same number of rows.

The following snippet implements this solution.

angular.module('myApp', [])
    .controller('myController', function ($scope){
    	$scope.myArray = {
          "My First Key" : [0, 1, 2, 'n'],
          "My Second Key" : ["Val0", "Val1", 'Val2', 'Valn'],
          "My Nth Key" : ['a0', 'a1', 'a2' , 'an']
        };
  
        $scope.pivotKey = Object.keys($scope.myArray)[0];
    });

angular.element(document).ready(function () {
  angular.bootstrap(document, ['myApp']);
});
table{
  border-collapse: collapse;
}
td,th {
  padding: 2px 4px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<table ng-controller="myController" border="1">
  <tr>
    <th ng-repeat="(column, rows) in myArray">{{ column }}</th>
  </tr>
  <tr ng-repeat="(rowIndex, rowValue) in myArray[pivotKey]">
    <td ng-repeat="value in myArray">
      {{ value[rowIndex] }}
    </td>
  </tr>
</table>