<html>
<head>
<title>Ng Repeat Start/End Demo</title>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-animate.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-loader.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-sanitize.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-cookies.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-touch.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-resource.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.14.3/ui-bootstrap.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.14.3/ui-bootstrap-tpls.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui-ieshiv.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="style.css">
<script type='text/javascript' src="script.js"></script>
</head>
<body ng-app="myApp">
<div ui-view="main" class="container-fluid"></div>
<script type="text/ng-template" id="state1.html">
<div class="row well">
<button class="btn btn-default" ng-click="vm.refresh()">Refresh</button>
</div>
<uib-accordion>
<uib-accordion-group ng-repeat="grp in vm.items | unique:'groupName' | orderBy:'groupName'" ng-init="state={isOpen: false}"
is-open="state.isOpen">
<uib-accordion-heading>
<span class="cursor-pointer">{{grp.groupName}} <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': state.isOpen, 'glyphicon-chevron-right': !state.isOpen}"></i></span>
</uib-accordion-heading>
<table class="table">
<tr class="item" ng-class-even="'even'" ng-class-odd="'odd'" ng-repeat-start="item in vm.items | filter:{groupName:grp.groupName}">
<td>
{{ item.market.name }}
<button class="btn btn-default" ng-click="vm.showHistory(item)" ng-bind="item.showHistory ? 'Hide History' : 'Show History'" />
</td>
<td ng-bind="item.runInfo.name"></td>
<td ng-bind="item.jobDetails.name"></td>
<td ng-bind="item.jobStats.name"></td>
</tr>
<tr class="history" ng-class-even="'even'" ng-class-odd="'odd'" ng-repeat-end ng-repeat="history in item.histories" ng-if="item.showHistory">
<td></td>
<td ng-bind="history.runInfo.name"></td>
<td ng-bind="history.jobDetails.name"></td>
<td ng-bind="history.jobStats.name"></td>
</tr>
</table>
</uib-accordion-group>
</uib-accordion>
</div>
</script>
</body>
</html>
(function () {
angular.module('myApp.services', ['ngResource', 'ngAnimate']);
angular.module('myApp.controllers', []);
angular.module('myApp.directives', []);
angular.module('myApp.filters', []);
var myApp = angular.module('myApp', [
'myApp.services',
'myApp.controllers',
'myApp.directives',
'myApp.filters',
'ngSanitize',
'ui.bootstrap',
'ui.router',
'ui']);
var uniqueFilter = function () {
return function (collection, propName) {
var result = [], keys = [];
angular.forEach(collection, function (item) {
var key = item[propName];
if (keys.indexOf(key) === -1) {
keys.push(key);
result.push(item);
}
});
return result;
};
};
uniqueFilter.$inject = ['$filter'];
angular.module('myApp')
.filter('unique', uniqueFilter);
var state1Ctrl = function ($timeout, $log, $filter) {
var vm = this,
initItems = function () {
vm.items = [];
var groups = [ 'Group1', 'Group2', 'Group3', 'Group4', 'Group5', 'Group6', 'Group7', 'Group8', 'Group9'];
var randItems = Math.floor(Math.random() * 50) + 1
for (var i = 0; i < randItems; i++) {
var item = {
name: "Item " + i.toString(),
showHistory: false,
market: { name: "Market " + i.toString() },
runInfo: { name: "RunInfo " + i.toString() },
jobDetails: { name: "JobDetails " + i.toString() },
jobStats: { name: "JobStats " + i.toString() },
groupName: groups[Math.floor(Math.random() * groups.length)],
randprop: Math.random()
};
item.histories = [];
var randHist = Math.floor(Math.random() * 3) + 1;
for (var j = 0; j < randHist; j++) {
var history = {
market: { name: "HistMarket " + j.toString() },
runInfo: { name: "HistRunInfo " + j.toString() },
jobDetails: { name: "HistJobDetails " + j.toString() },
jobStats: { name: "HistJobStats " + j.toString() },
randprop: Math.random()
};
// Randomly clear some of the history
history.runInfo.name = (Math.floor(Math.random() * 100) + 1) > 30 ? history.runInfo.name : "";
history.jobDetails.name = (Math.floor(Math.random() * 100) + 1) > 50 ? history.jobDetails.name : "";
history.jobStats.name = (Math.floor(Math.random() * 100) + 1) > 50 ? history.jobStats.name : "";
item.histories.push(history);
}
vm.items.push(item);
}
},
init = function () {
$timeout(function () {
setTimeout(initItems(), 1000)
}, 0);
};
vm.refresh = function() {
initItems();
};
vm.showHistory = function (item) {
item.showHistory = !item.showHistory;
};
vm.toggleAll = function () {
angular.forEach(vm.items, function(item) {
item.showHistory = !item.showHistory;
});
}
init();
};
state1Ctrl.$inject = ['$timeout', '$log', '$filter'];
angular.module('myApp.controllers')
.controller('state1Ctrl', state1Ctrl);
myApp.config(['$locationProvider', '$stateProvider', '$urlRouterProvider',
function ($locationProvider, $stateProvider, $urlRouterProvider) {
$locationProvider.html5Mode(false);
$urlRouterProvider.when('/', '/state1')
.otherwise("/state1");
$stateProvider.state('app', {
abstract: true,
url: '/',
views: {
'main': {
template: '<div ui-view>/div>'
}
}
})
.state('app.state1', {
url: 'state1',
templateUrl: 'state1.html',
controller: 'state1Ctrl',
controllerAs: 'vm',
reloadOnSearch: false
})
}]);
myApp.run(['$log', function ($log) {
$log.log("Start.");
}]);
})()
multiselect {
display: block;
}
multiselect > .btn-group {
min-width: 180px;
}
multiselect .btn {
width: 100%;
background-color: #FFF;
}
multiselect .btn.has-error {
border: 1px solid #a94442 !important;
color: #db524b;
}
multiselect .dropdown-menu {
max-height: 300px;
min-width: 200px;
overflow-y: auto;
}
multiselect .dropdown-menu .filter > input {
width: 99%;
}
multiselect .dropdown-menu .filter .glyphicon {
cursor: pointer;
pointer-events: all;
}
multiselect .dropdown-menu {
width: 100%;
box-sizing: border-box;
padding: 2px;
}
multiselect > .btn-group > button {
padding-right: 20px;
}
multiselect > .btn-group > button > .caret {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid black;
right: 5px;
top: 45%;
position: absolute;
}
multiselect .dropdown-menu > li > a {
padding: 3px 10px;
cursor: pointer;
}
multiselect .dropdown-menu > li > a i {
margin-right: 4px;
}
.glyphicon-none:before {
content: "\e013";
color: transparent !important;
}
.item.odd {
background-color: #f9f9f9;
}
.item:hover {
background-color: #f5f5f5;
}
.history.odd {
background-color: #bfccdd;
}
.history.even {
background-color: #a7b4c5;
}
.history:hover
{
background-color: #99a4b2;
}
.group {
font-size:1.4em;
font-weight: bolder;
}
}
This demo shows how to use ng-repeat-start and ng-repeat-end to generate a table with parent/child information.