0

Let us assume we have following data structure:

var data = [
   {
      name: "item name",
      nestedData: [{
         name: "nested name",
         quantity: 1
      },
      {
         name: "nested name 2",
         quantity: 2
      }
      ]
   },
   {
      name: "item name 2",
      nestedData: [{
         name: "nested name 3",
         quantity: 3
      }
      ]
   }
];

Standard behavior of ng-repeat directive will iterate over high level elements. If we run ng-repeat="item in data" it will produce two items.

Is it possible - without using custom directive - to iterate over first item ("item name") twice (multiply it by a length of nestedData array)?

The output I'd like to achieve is:

<table>
   <thead>
      <th>Name</th>
      <th>Nested name</th>
      <th>Nested quantity</th>
   </thead>
   <tbody>
      <tr>
         <td rowspan="2">item name</td>
         <td>nested name</td>
         <td>1</td>
      </tr>
      <tr>
        <td ng-hide="true">item name</td>
        <td>nested name 2</td>
        <td>2</td>
      </tr>
      <tr>
        <td>item name 2</td>
        <td>nested name 3</td>
        <td>3</td>
      </tr>
   </tbody>
</table>

Nested ng-repeat is not suitable in this situation because there's a need to iterate over <tr>'s.

17
  • first you mas aplain your array, in one level use map, with recursive method to access at lower Commented Feb 20, 2017 at 11:00
  • Can you tell us how your result looks like Commented Feb 20, 2017 at 11:01
  • 1
    @Landeeyo what is the expected output would look like, just add it to your question Commented Feb 20, 2017 at 11:11
  • 2
    @Landeeyo that's what is being output. jsfiddle.net/zyp9kqqL/1 to make sure it's being done like that you can add an orderBy to the ng-repeat Commented Feb 20, 2017 at 11:12
  • 1
    You can still do this with nested ng-repeat, it's valid HTML to have one table with multiple tbodys, updated fiddle, this is with the working rowspan Commented Feb 20, 2017 at 11:33

2 Answers 2

3

You can use a nested ng-repeat to get your desired result as it's valid HTML to have multiple tbody elements.

Here is a JSFiddle for a working example

<table>
    <thead>
      <th>Name</th>
      <th>Nested name</th>
      <th>Nested quantity</th>
    </thead>
    <tbody ng-repeat="item in data">
          <tr ng-repeat="nestedItem in item.nestedData">
            <td rowspan="{{item.nestedData.length}}" ng-hide="$index == 1">{{item.name}}</td>
            <td>{{nestedItem.name}}</td>
            <td>{{nestedItem.quantity}}</td>
          </tr>
    </tbody>
  </table>
Sign up to request clarification or add additional context in comments.

1 Comment

Many thanks George :). I didn't know it's possible to set ng-repeat on tbody. Great solution.
1

It's a different approach to achieve expected output.

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
    var data = [
         {
            name: "item name",
              nestedData: [
              {
                 name: "nested name",
                 quantity: 1
              },
              {
                 name: "nested name 2",
                 quantity: 2
              },
              {
                 name: "nested name 3",
                 quantity: 3
              }
            ]
         },
         {
            name: "item name 2",
              nestedData: [{
                 name: "nested name 3",
                 quantity: 3
              }
            ]
         }
      ];
 
  var nestedData = [];
  angular.forEach(data, function(item){
    if(item.nestedData.length > 1){
      angular.forEach(item.nestedData, function(nestedItem){
        nestedData.push({
          name : item.name,
          nestedName: nestedItem.name,
          nestedQty: nestedItem.quantity,
          colspan: item.nestedData.length
        });
      });
    } else {
      nestedData.push({
        name : item.name,
        nestedName: item.nestedData[0].name,
        nestedQty: item.nestedData[0].quantity
      });
    }
  });
  
  $scope.data = nestedData;
});
tr.multiple > td:first-child {
  display: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<div class="container" ng-app="myApp" ng-controller="myCtrl">
  
<table class="table table-stripped">
   <thead>
      <th>Name</th>
      <th>Nested name</th>
      <th>Nested quantity</th>
   </thead>
   <tbody>
      <tr ng-repeat="item in data" ng-class="{'multiple': item.colspan > '1' && !$first}">
         <td rowspan="{{item.colspan ? item.colspan : '1'}}">{{item.name}}</td>
         <td>{{item.nestedName}}</td>
         <td>{{item.nestedQty}}</td>
      </tr>
   </tbody>
</table>
  
</div>

1 Comment

Thank you Vilas. I decided to mark George's answer as correct because it's simpler in given example, but I find your solution also very informative, it can be helpful especially in more complex cases. Thank you very much.

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.