0

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.

7
  • 4
    can you make a plunker with the code you tried? Commented Jun 23, 2017 at 6:46
  • have you tried? put your code here which you have already tried. Commented Jun 23, 2017 at 7:00
  • Your array will contain only one object? Commented Jun 23, 2017 at 7:09
  • This question was too broad :( Commented Jun 23, 2017 at 7:13
  • @Vivz no it can contain multiple objects. Commented Jun 23, 2017 at 7:20

2 Answers 2

3

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for this! I was wondering if there's a solution without creating separate arrays in the controller?
@NishantRoy, you have three tables, so you will have three arrays. As I already wrote, it will be very complicated to solve this problem with only one table and initial array, because of need to implement very complicated html structure of resulting table.
0

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

Comments

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.