1

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?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
EnigmaRM
  • 7,523
  • 11
  • 46
  • 72
  • Why cant you nest ng-repeats? – smk Jun 19 '13 at 18:25
  • @smk I know you can nest ng-repeats. But I haven't been able to get it to work correctly when using tables. How would you go about doing it? – EnigmaRM Jun 19 '13 at 18:31
  • And after a certain point, what are you going to nest on? `` doesn't have children, unless I'm mistaken. And in the near future, I'll have projects where the object goes 4-5 levels deep... I have no idea what I'll do in those cases if I can't even get this one to work. ha. – EnigmaRM Jun 19 '13 at 19:10

3 Answers3

6

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

Bastien Caudan
  • 4,482
  • 1
  • 17
  • 29
  • it is not always a number. Well within the sample code I gave you it is. But in the larger dataset, there are decimals and text values as well. – EnigmaRM Jun 19 '13 at 21:16
  • I modified my answer to deal with others data types – Bastien Caudan Jun 19 '13 at 22:14
  • 1
    I like this solution. I haven't yet tried the directive approach. Attempting to use ng-switch first. But the typeOf() always returns undefined. Not sure why. To simplify things a bit more, I am trying to use `angular.isObject()`. And then switch on `true`. But no luck with that yet either. – EnigmaRM Jun 20 '13 at 16:05
  • I add a fork of your plunker with the ng-switch – Bastien Caudan Jun 21 '13 at 11:22
  • Thanks. I ended up getting something to work yesterday. The sample plunker I provided was a very dumbed down version of what was actually going on. But I eventually got it working with `ng-switch`. Appreciate the help. Your solution above was great. – EnigmaRM Jun 21 '13 at 14:37
  • angular.isObject() isn't working for me at all. Bastiens solution works fine – alexdd55 Oct 07 '14 at 09:07
1

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.

Community
  • 1
  • 1
Mathew Berg
  • 28,625
  • 11
  • 69
  • 90
1

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">
Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113