EnigmaRM
EnigmaRM

Reputation: 7632

How to ng-repeat into html table with multiple levels of json?

I have an object of social media stats. I'm trying to ng-repeat them into a table. Here's my plunker.

HTML:

<table>
      <tr ng-repeat="(metric, metricData) in data">
        <td>{{metric}}</td>
        <td>{{metricData}}</td>
      </tr>
</table>

Controller object:

 $scope.data = { buzz:0, 
                  Delicious:121,
                  Facebook: 
                  { 
                    like_count: "6266",
                    share_count: "20746"
                  },
                  GooglePlusOne:429,
                  LinkedIn:820,
                  Twitter:4074
                };

I run into a problem when I get to the Facebook results. Within the <td> that entire object gets displayed (as it should be with how I have my code setup). But what I'd rather have happen is to repeat through that object and display the key and value in the cell.

I tried doing something looking to see if metricData is an object and doing some sort of ng-repeat on that. But I wasn't having luck with that. Any idea on how I can display the inner object (keys & value) within the cells?

Upvotes: 1

Views: 6740

Answers (3)

Bastien Caudan
Bastien Caudan

Reputation: 4490

You can define a scope function returning the type of metricData :

  $scope.typeOf = function(input) {
    return typeof input;
  }

And then you can display it according to its type :

  <tr ng-repeat="(metric, metricData) in data">
    <td>{{metric}}</td>
    <td ng-switch on="typeOf(metricData)">
      <div ng-switch-when="object">
        <div ng-repeat="(key, value) in metricData">
          <span>{{key}}</span>
          <span>{{value}}</span>
        </div>
      </div> 
      <span ng-switch-default>{{metricData}}</span>  
    </td>
  </tr>

You can see it in this Plunker

Upvotes: 6

Jason Goemaat
Jason Goemaat

Reputation: 29194

I'm assuming you want each of those values to have their own line but you don't explain exactly how you want it to work. I think the matter would best be handled by passing a clean version of what you want to the ng-repeat directive. I'm assuming you want two rows for facebook in your sample. You could create a filter to flatten the metrics so there are properties "Facebook_like_count" and "Facebook_share_count" (PLUNKER):

app.filter('flatten', function() {
  function flattenTo(source, dest, predicate) {
    predicate = predicate || '';
    angular.forEach(source, function(value, key) {
      if (typeof(value) == 'object') {
        flattenTo(value, dest, predicate + key + '_');
      } else {
        dest[predicate + key] = value;
      }
    });
  }

  return function(input) {
    var obj = {};
    flattenTo(input, obj, '');
    return obj;
  }
});

Then your repeat can use the filter:

<tr ng-repeat="(metric, metricData) in data|flatten">

Upvotes: 1

Mathew Berg
Mathew Berg

Reputation: 28750

Sounds like you'll need a specific directive that wires up children to be recursive, take a look at this example: Recursion in Angular directives

What you'd check on is if what you need to repeat is an object and not a value, then add the new element compile it, and start the process over again.

Upvotes: 1

Related Questions