Nishant Roy
Nishant Roy

Reputation: 1141

Nested rows in Angular Table

I have a JSON array like this:

[
  {
    "students": {
      "Student1": {
        "number": "15",
        "books": {
          "Mystery": [
            "Book1",
            "Book2"
          ]
        }
      },
      "Student2": {
        "number": "12",
        "books": {
          "Romance": [
            "Book1"
          ],
          "Adventure": [
            "Book1",
            "Book2"
          ]
        }
      },
      "Student3": {
        "number": "116",
        "books": {
        }
      }
    },
    "class": "7th Grade",
    "school": "High School 1"
  }
]

I want to display this data as a table on an Angular1 page in the following manner: Table Desired

How can I make it so that the columns resize with each other, and how can I have nested ng-repeats as needed?

I tried to have nested tables inside the student, student-number, and books columns, and a table within the table in the books column, but the alignment was always off, and I couldn't get a default value of "No Books" to show up if the "books" field was empty.

Here's a Plunkr of what I've tried so far.

Upvotes: 0

Views: 1115

Answers (2)

Nishant Roy
Nishant Roy

Reputation: 1141

I chose to create hidden nested tables to show more information upon click.

Upvotes: 0

Slava Utesinov
Slava Utesinov

Reputation: 13498

One of possible solutions is to combine several tables(based on $scope.base, $scope.students, $scope.books arrays, that calculated in controller) into one virtual, desired table via float:left(to ensure they located in one row). Docking of rows is provided by setting of their style:height, which depends on number of their children. Direct solution will be very complicated due to complicated html markup of table with rowspan attributes. Also I added second item(items.push(items[0])), to demonstrate, that solution works at case of several items.

angular.module('app', [])
.controller('MyController', ['$scope', function($scope) {
    var items = [
    {
      "students": {
        "Student1": {
          "number": "15",
          "books": {
            "Mystery": [
              "Book1",
              "Book2"
            ]
          }
        },
        "Student2": {
          "number": "12",
          "books": {
            "Romance": [
              "Book1"
            ],
            "Adventure": [
              "Book1",
              "Book2"
            ]
          }
        },
        "Student3": {
          "number": "116",
          "books": {
          }
        },
        "class": "7th Grade",
        "school": "High School 1"
      }
    }
  ];
  items.push(items[0]);
   
   $scope.base = [];
   $scope.students = [];
   $scope.books = [];
   for(var item of items){
      var temp = $scope.books.length;
      for(var student in item.students){
        if(['class', 'school'].indexOf(student) == -1){
           var studentV = item.students[student];
           $scope.students.push({name:student, number: studentV.number, w: Object.keys(studentV.books).length || 1});
           for(var book in studentV.books)
              $scope.books.push((book + ':' + JSON.stringify(studentV.books[book])).replace(/"/g, ''));       
           if(Object.keys(studentV.books).length == 0)
             $scope.books.push('No books');
        }
      } 
      $scope.base.push({cl: item.students.class, school: item.students.school, w: $scope.books.length - temp});
   }
   
}]);
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
}
table.left, table.left th, table.left td {
    border-right: 0px
}
tr {
  text-align:center
}
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>

<div ng-app='app' ng-controller="MyController">           
  <table style='float:left;border-right:0' class='left'>
      <thead>
        <tr>
          <th>School</th>
          <th>Class</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat='item in base' style='height:{{item.w*30}}px'>
          <td>{{item.school}}</td>
          <td>{{item.cl}}</td>
        </tr>
      </tbody>
  </table>

  <table style='float:left' class='left'>
      <thead>
        <tr>
          <th>Student</th>
          <th>Student-number</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat='item in students' style='height:{{item.w*30}}px'>
          <td>{{item.name}}</td>
          <td>{{item.number}}</td>
        </tr>
      </tbody>
  </table>

  <table>
      <thead>
        <tr>
          <th>Books</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat='item in books track by $index' style='height:30px'>
          <td>{{item}}</td>
        </tr>
      </tbody>
  </table>

</div>

Upvotes: 3

Related Questions