Manav Saxena
Manav Saxena

Reputation: 473

Html/Angular toggle table rows to show hidden a table

I am completely new to angular, I need to create a table. The data array is as-follows:-

data = [{rollno: 1,name: 'abc',subject: 'maths'},
        {rollno: 4,name: 'xyz',subject: 'history'},
        {rollno: 2,name: 'pqr',subject: 'history'}
       ];

I want to create a table with some summary rows based on this data and then when I click the expand button the sub-rows should appear beneath that summary-row indicating the actual data.

For example:-

Expand/Collapse | No of Students | Subject
 click here        1                Maths
 click here        2               History

When I toggle the expand/collapse button on the second row for example I want actual rows to appear like this beneath it:-

 Expand/Collapse | No of Students | Subject
 click here        1                Maths
 click here        2               History
 RollNo | StudentName
   4       xyz
   2       pqr

How Can I achieve this?

Upvotes: 1

Views: 5806

Answers (4)

Matthew Cawley
Matthew Cawley

Reputation: 2818

1) Grouping the data by subject

First you need to group the data by subject and then count the items in each group.

You can use the angular.filter module's groupBy filter to do this.

1a) Add a dependency on that module as follows:

var app = angular.module("yourModuleName", ["angular.filter"]);

1b) You can then use the groupBy filter in an ng-repeat directive on a <tbody> tag like this:

<tbody ng-repeat="(key, value) in data | groupBy: 'subject'">

1c) You're now dealing with the data in the format below. This is an object of key/value pairs where "maths" and "history" are both keys, and the arrays are the values

{
  "maths": [
    {
      "rollno": 1,
      "name": "abc",
      "subject": "maths",
    }
  ],
  "history": [
    {
      "rollno": 4,
      "name": "xyz",
      "subject": "history",
    },
    {
      "rollno": 2,
      "name": "pqr",
      "subject": "history",
    }
  ]
}

2) Displaying the grouped data and counting the items in each group

Use key and value to display the grouped data in a table as follows:

<table>
  <thead>
    <tr>
      <th>Subject</th>
      <th>Number of Students</th>
      <th>Expand/Collapse</th>
    </tr>
  </thead>
  <tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
    <tr>
      <td>{{ key }}</td>
      <td>{{ value.length }}</td>
      <td>
        <button>
          Expand/Collapse
        </button>
      </td>
    </tr>
    <tr>
      <td colspan="3">
        <table>
          <thead>
            <tr>
              <th>Roll Number</th>
              <th>Name</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="student in value">
              <td>{{ student.rollno }}</td>
              <td>{{ student.name }}</td>
            </tr>
          </tbody>
        </table>
      </td>
    </tr>
  </tbody>
</table>

Note the extra <tr> and nested table with another ng-repeat for displaying the student data. Currently all nested student data will display, the next step is to conditionally show/hide the nested tables based on which expand/collapse button was clicked.

3) Showing/Hiding the nested student data

3a) Add an ng-click directive on the button so that it passes in the key to an onExpandClicked function on your controller:

<button ng-click="onExpandClicked(key)">
  Expand/Collapse
</button>

3b) Create the onExpandClicked function in your controller:

$scope.onExpandClicked = function(name){
  $scope.expanded = ($scope.expanded !== name) ? name : "";
}

This sets a value on the $scope that can be used in the view to decide whether to show/hide a section of student data. The key is passed into the function as the name parameter and $scope.expanded will either be set to name or reset to "" depending on whether the passed in name is the same as the current $scope.expanded value or not.

3c) Finally, use the $scope.expanded variable in an ng-if directive on the second <tr> tag of <tbody> to show or hide the nested student data:

<table>
  <thead>
    <tr>
      <!-- Omitted for brevity -->
   </tr>
  </thead>
  <tbody ng-repeat="(key, value) in data | groupBy: 'subject'">
    <tr>
      <!-- Omitted for brevity -->
    </tr>
    <tr ng-if="expanded === key">
      <!-- 
        Omitted for brevity 
      -->
    </tr>
  </tbody>
</table>

Demo

CodePen: How to show/hide grouped data created by the angular.filter module's groupBy filter

Upvotes: 2

Akshay Kalola
Akshay Kalola

Reputation: 196

Here is a working example which resolves your problem.

var indexCtrl = ['$scope', function($scope){
  $scope.num = 0;
  $scope.test = [{rollno: 1,name: 'abc',subject: 'maths'},
        {rollno: 4,name: 'xyz',subject: 'history'},
        {rollno: 2,name: 'pqr',subject: 'history'}
       ];
  $scope.changeShow = function(index){
    $scope.num = index;
  };
}];
<!DOCTYPE html>
<html ng-app>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body ng-controller='indexCtrl'>
<table>
  <tr>
  <td>Expand/Collapse</td>
  <td>No of Students</td>
  <td>Subject</td>
  </tr>
  <tr ng-repeat='i in test' ng-class="num == $index ? red : none">{{}}
    <td ng-click='changeShow($index)'><a href="javascript:void(0)">click here</a></td>
    <td>{{$index +1}}</td>
    <td >{{i.subject}}</td>
   </tr>
</table>
  <table>
  <tr>
  <td>RollNo</td>
  <td>StudentName</td>
  </tr>
  <tr ng-repeat='i in test'>
    <td ng-show='num == $index'>{{i.rollno}}</td>
     <td ng-show='num == $index'>{{i.name}}</td>
  </tr>
</table>
  <style>
   table tr td{
        border: 1px solid black
    }
</style>
</body>
</html>

Hope it helps you.

Upvotes: 0

scipper
scipper

Reputation: 3153

First you should replace the actual table by a div structure, because it is not possible to mix two kinds of table like you are planning (when I get you right).

You could toggle every row with a ng-click with the corresponding expanded content like this (pseudo code, I hope the idea gets clear):

<div class="row-header">
  <span>RollNo</span>
  <span>StudentName</span>
</div>

<div class="row-content" ng-if="!row_4_expanded" ng-click="row_4_expanded = !row_4_expanded">
  <span>4</span>
  <span>xyz</span>
</div>

<div ng-if="row_4_expanded">
  <div class="row-expanded-header">
    <span>No of Students</span>
    <span>Subject</span>
  </div>
  <div class="row-expanded-content">
    <span>1</span>
    <span>Math</span>
  </div>
  <div class="row-expanded-content">
    <span>2</span>
    <span>History</span>
  </div>
</div>


<div class="row-content" ng-if="!row_2_expanded" ng-if="row_2_expanded" ng-click="row_2_expanded = !row_2_expanded">
  <span>2</span>
  <span>pqr</span>
</div>

<div ng-if="row_2_expanded">
  <div class="row-expanded-header">
    <span>No of Students</span>
    <span>Subject</span>
  </div>
  <div class="row-expanded-content">
    <span>1</span>
    <span>Math</span>
  </div>
  <div class="row-expanded-content">
    <span>2</span>
    <span>History</span>
  </div>
</div>

When you now click on a row, it toggle presens with the corresponding expanded one.

Upvotes: 0

anteAdamovic
anteAdamovic

Reputation: 1468

Design a table with html and iterate through your data object with ng-repeat loop to display the data.

ngRepeat

W3Schools has some basic examples on how to display tables with AngularJS

Angular Tables

Upvotes: 0

Related Questions