根据 json 数据的值对 html 数据中的行进行分组。并在点击每个显示详细信息的值时展开行
Group rows in html data based on json data's value. And expand row when tapped on each value showing details
我有一个JSON数据如下:
{
"data": [{
"appDetails": [{
"appDescription": [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
}]
}]}
我的 angular js 代码是关于 http.get
方法从 cloudant 数据库中获取上述 json 并使用 $scope
将数据推送到 html table。
Angular js代码:
function DashboardTablesPageCtrl($scope,$http,$timeout) {
$scope.tableData = [];
$scope.myFilter = ""
var req = {
method: 'POST',
url: 'https://'+ACCOUNTNAME+'.cloudant.com/_session',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: 'name='+APIKEY+'&password='+APIPASSWORD,
withCredentials: true
}
$http(req).then(function(result){
//Grab data
req = {
method: 'GET',
url: 'https://'+ACCOUNTNAME+'.cloudant.com/'+DATABASE+'/_all_docs',
withCredentials: true
}
var i = 0;
$timeout(function(){
$http(req).then(function(result){
for(i=0;i<result.data.total_rows;i++){
var id = result.data.rows[i].id
$http.get('https://'+ACCOUNTNAME+'.cloudant.com/'+DATABASE+'/'+id).then(function(data){
var data = data.data
angular.forEach(data.data[0].appDetails, function(appDetail, index) {
angular.forEach(appDetail.appDescription, function(appDescription, index){
$scope.tableData.push(appDescription);
});
});
})
}
},
function(){
console.log("Failed at grabbing data");
});
},
function(){
console.log('Failed at authenticating');
});
});}})();
我在我的 html table正文中使用了 ng-repeat 来显示如下数据:
<tbody>
<tr ng-repeat="item in tableData | filter: myFilter ">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
这会在不同的行中显示所有数据。我需要将 App X、App Y 和 App Z 的所有数据分组,并且只显示三行,点击 App X 应该通过展开相同 table 中的行来显示 App X 的数据。
我无法实现这一点,因为我在 table 上的每个数据只获得了不同的行。请帮助我实现这一目标。
想法是当用户单击具有应用名称的行时显示和隐藏给定应用名称的行。
这可以通过仅包含应用程序名称的行(单击它们)和按应用程序名称过滤的行来实现:
<tr><td colspan="10" ng-click=swapExpandingX()>App X</td></tr>
<tr ng-show="expandX" ng-repeat="item in tableData | filter: { appName: 'App X'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
<tr><td colspan="10" ng-click=swapExpandingY()>App Y</td></tr>
<tr ng-show="expandY" ng-repeat="item in tableData | filter: { appName: 'App Y'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
并在点击调用的控制器中交换功能:
$scope.expandX = false;
$scope.swapExpandingX = function() {
$scope.expandX = !$scope.expandX;
}
在下面的代码片段中查看它是如何工作的。
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.expandX = false;
$scope.expandY = false;
$scope.swapExpandingX = function() {
$scope.expandX = !$scope.expandX;
}
$scope.swapExpandingY = function() {
$scope.expandY = !$scope.expandY;
}
$scope.tableData = [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tbody>
<tr><td colspan="10" ng-click=swapExpandingX()>App X</td></tr>
<tr ng-show="expandX" ng-repeat="item in tableData | filter: { appName: 'App X'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
<tr><td colspan="10" ng-click=swapExpandingY()>App Y</td></tr>
<tr ng-show="expandY" ng-repeat="item in tableData | filter: { appName: 'App Y'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
</div>
删除代码重复
好的,它有效。现在我们可以通过删除 html 和 controller.
中的代码重复来改进此代码。
让我们将 appNames 存储在数组 appNames
中。您可以对其进行硬编码
$scope.appNames = ["App X", "App Y", "App Z"];
或从 tableData
中动态检索
$scope.appNames = Array.from(new Set($scope.tableData.map(a => a.appName)));
如果要扩展给定应用名称的行,我们将需要结构来存储信息。让我们创建映射 expanding
并为每个应用程序名称设置 false
值作为键。
$scope.expanding = {};
for (index = 0; index < $scope.appNames.length; index++) {
$scope.expanding[$scope.appNames[index]] = false;
}
现在我们可以 html 没有重复:
<table>
<tbody ng-repeat="name in appNames">
<tr>
<td colspan="10" ng-click=swapExpanding(name)>{{name}}</td>
</tr>
<tr ng-show="expanding[name]" ng-repeat="item in tableData | filter: { appName: name}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
和简单的交换功能:
$scope.swapExpanding = function(name) {
$scope.expanding[name] = !$scope.expanding[name];
}
在下面的代码片段中查看它是如何工作的。
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.tableData = [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
$scope.appNames = Array.from(new Set($scope.tableData.map(a => a.appName)));;
$scope.expanding = {};
for (index = 0; index < $scope.appNames.length; index++) {
$scope.expanding[$scope.appNames[index]] = false;
}
$scope.swapExpanding = function(name) {
$scope.expanding[name] = !$scope.expanding[name];
}
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tbody ng-repeat="name in appNames">
<tr>
<td colspan="10" ng-click=swapExpanding(name)>{{name}}</td>
</tr>
<tr ng-show="expanding[name]" ng-repeat="item in tableData | filter: { appName: name}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
</div>
我有一个JSON数据如下:
{
"data": [{
"appDetails": [{
"appDescription": [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
}]
}]}
我的 angular js 代码是关于 http.get
方法从 cloudant 数据库中获取上述 json 并使用 $scope
将数据推送到 html table。
Angular js代码:
function DashboardTablesPageCtrl($scope,$http,$timeout) {
$scope.tableData = [];
$scope.myFilter = ""
var req = {
method: 'POST',
url: 'https://'+ACCOUNTNAME+'.cloudant.com/_session',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: 'name='+APIKEY+'&password='+APIPASSWORD,
withCredentials: true
}
$http(req).then(function(result){
//Grab data
req = {
method: 'GET',
url: 'https://'+ACCOUNTNAME+'.cloudant.com/'+DATABASE+'/_all_docs',
withCredentials: true
}
var i = 0;
$timeout(function(){
$http(req).then(function(result){
for(i=0;i<result.data.total_rows;i++){
var id = result.data.rows[i].id
$http.get('https://'+ACCOUNTNAME+'.cloudant.com/'+DATABASE+'/'+id).then(function(data){
var data = data.data
angular.forEach(data.data[0].appDetails, function(appDetail, index) {
angular.forEach(appDetail.appDescription, function(appDescription, index){
$scope.tableData.push(appDescription);
});
});
})
}
},
function(){
console.log("Failed at grabbing data");
});
},
function(){
console.log('Failed at authenticating');
});
});}})();
我在我的 html table正文中使用了 ng-repeat 来显示如下数据:
<tbody>
<tr ng-repeat="item in tableData | filter: myFilter ">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
这会在不同的行中显示所有数据。我需要将 App X、App Y 和 App Z 的所有数据分组,并且只显示三行,点击 App X 应该通过展开相同 table 中的行来显示 App X 的数据。
我无法实现这一点,因为我在 table 上的每个数据只获得了不同的行。请帮助我实现这一目标。
想法是当用户单击具有应用名称的行时显示和隐藏给定应用名称的行。 这可以通过仅包含应用程序名称的行(单击它们)和按应用程序名称过滤的行来实现:
<tr><td colspan="10" ng-click=swapExpandingX()>App X</td></tr>
<tr ng-show="expandX" ng-repeat="item in tableData | filter: { appName: 'App X'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
<tr><td colspan="10" ng-click=swapExpandingY()>App Y</td></tr>
<tr ng-show="expandY" ng-repeat="item in tableData | filter: { appName: 'App Y'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
并在点击调用的控制器中交换功能:
$scope.expandX = false;
$scope.swapExpandingX = function() {
$scope.expandX = !$scope.expandX;
}
在下面的代码片段中查看它是如何工作的。
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.expandX = false;
$scope.expandY = false;
$scope.swapExpandingX = function() {
$scope.expandX = !$scope.expandX;
}
$scope.swapExpandingY = function() {
$scope.expandY = !$scope.expandY;
}
$scope.tableData = [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tbody>
<tr><td colspan="10" ng-click=swapExpandingX()>App X</td></tr>
<tr ng-show="expandX" ng-repeat="item in tableData | filter: { appName: 'App X'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
<tr><td colspan="10" ng-click=swapExpandingY()>App Y</td></tr>
<tr ng-show="expandY" ng-repeat="item in tableData | filter: { appName: 'App Y'}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
</div>
删除代码重复
好的,它有效。现在我们可以通过删除 html 和 controller.
中的代码重复来改进此代码。让我们将 appNames 存储在数组 appNames
中。您可以对其进行硬编码
$scope.appNames = ["App X", "App Y", "App Z"];
或从 tableData
$scope.appNames = Array.from(new Set($scope.tableData.map(a => a.appName)));
如果要扩展给定应用名称的行,我们将需要结构来存储信息。让我们创建映射 expanding
并为每个应用程序名称设置 false
值作为键。
$scope.expanding = {};
for (index = 0; index < $scope.appNames.length; index++) {
$scope.expanding[$scope.appNames[index]] = false;
}
现在我们可以 html 没有重复:
<table>
<tbody ng-repeat="name in appNames">
<tr>
<td colspan="10" ng-click=swapExpanding(name)>{{name}}</td>
</tr>
<tr ng-show="expanding[name]" ng-repeat="item in tableData | filter: { appName: name}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
...
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
和简单的交换功能:
$scope.swapExpanding = function(name) {
$scope.expanding[name] = !$scope.expanding[name];
}
在下面的代码片段中查看它是如何工作的。
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.tableData = [{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.25",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.24",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App X",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.23",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Y",
"timeStamp": "",
"GitTag": "RELEASE-1.0.1.2",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.0",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
},
{
"appName": "App Z",
"timeStamp": "",
"GitTag": "RELEASE-1.0.0.1",
"blocker": "3",
"critical": "4",
"major": "30",
"minor": "2",
"UnitTestsTotal": "59",
"FailedTests": "0",
"CodeCoverage": "90"
}
]
$scope.appNames = Array.from(new Set($scope.tableData.map(a => a.appName)));;
$scope.expanding = {};
for (index = 0; index < $scope.appNames.length; index++) {
$scope.expanding[$scope.appNames[index]] = false;
}
$scope.swapExpanding = function(name) {
$scope.expanding[name] = !$scope.expanding[name];
}
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tbody ng-repeat="name in appNames">
<tr>
<td colspan="10" ng-click=swapExpanding(name)>{{name}}</td>
</tr>
<tr ng-show="expanding[name]" ng-repeat="item in tableData | filter: { appName: name}">
<td>{{item.appName}}</td>
<td>{{item.GitTag}}</td>
<td>{{item.blocker}}</td>
<td>{{item.critical}}</td>
<td>{{item.major}}</td>
<td>{{item.minor}}</td>
<td>{{item.UnitTestsTotal}}</td>
<td>{{item.FailedTests}}</td>
<td>{{item.CodeCoverage}}</td>
</tr>
</tbody>
</table>
</div>