<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<link data-require="font-awesome@4.3.0" data-semver="4.3.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
<script data-require="bootstrap@3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script data-require="angular.js@1.4.6" data-semver="1.4.6" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src="directives.js"></script>
<script src="filters.js"></script>
</head>
<body ng-app="app">
<div ng-controller="TestCtrl">
<table-sortable columns="columns"
data="rows"
sort="sort">
</table-sortable>
</div>
</body>
</html>
// Code goes here
angular.module('app', ['app.controllers', 'app.directives', 'app.filters']);
angular.module('app.controllers', [])
.controller('TestCtrl', [
'$scope', '$timeout', function ($scope, $timeout) {
//Randomly enter data for rows
$scope.rows = [];
for(var i = 1; i <= 52; i++){
$scope.rows.push({
'Id': i,
'Name': Math.random().toString(36).substring(7),
'Amount': Math.floor((Math.random() * 12345)),
'Date': new Date(new Date() - (Math.floor((Math.random() * 12345)) * 100000000))
})
}
$scope.columns = [
{
display: 'Loop Number', //The text to display
variable: 'Id', //The name of the key that's apart of the data array
filter: 'number : 0' //The type data type of the column (number, text, date, etc.)
},
{
display: 'Name', //The text to display
variable: 'Name', //The name of the key that's apart of the data array
filter: 'text' //The type data type of the column (number, text, date, etc.)
},
{
display: 'Amount', //The text to display
variable: 'Amount', //The name of the key that's apart of the data array
filter: 'number : 0' //The type data type of the column (number, text, date, etc.)
},
{
display: 'DateTime', //The text to display
variable: 'Date', //The name of the key that's apart of the data array
filter: 'dateTime' //The type data type of the column (number, text, date, etc.)
}
];
$scope.sort = {
column: 'Id', //to match the variable of one of the columns
descending: false
};
}
]);
.table-sortable > thead > tr > th {
cursor: pointer;
position: relative;
background-image: none !important;
}
.table-sortable > thead > tr > th:after,
.table-sortable > thead > tr > th.sort-false:after,
.table-sortable > thead > tr > th.sort-true:after {
font-family: FontAwesome;
padding-left: 5px;
}
.table-sortable > thead > tr > th:after {
content: "\f0dc";
color: #ddd;
}
.table-sortable > thead > tr > th.sort-false:after {
content: "\f0de";
color: #767676;
}
.table-sortable > thead > tr > th.sort-true:after {
content: "\f0dd";
color: #767676;
}
ul.pagination > li:not(.active){
cursor: pointer;
}
<table class="table table-hover table-striped table-sortable">
<thead>
<tr>
<th
ng-repeat="column in columns"
ng-class="selectedClass(column.variable)"
ng-click="changeSorting(column.variable)">
{{column.display}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="object in data | orderBy:sort.column:sort.descending | orderBy:sort.column:sort.descending | startFrom:currentPage*pageSize | limitTo:pageSize">
<td
ng-repeat="key in object"
ng-if="key != '$$hashKey'" >
{{object[columns[$index].variable] | customFilter : getFilterOfColumn(columns[$index].variable)}}
</td>
</tr>
</tbody>
<tfoot>
<tr ng-show="numberOfPages > 1">
<td colspan="{{columns.length}}">
<div style="float: left">
<button class="btn btn-primary"
ng-click="changePage(currentPage - 1)"
ng-disabled="currentPage == 0">
Previous
</button>
{{currentPage + 1}} / {{numberOfPages}}
<button class="btn btn-primary"
ng-click="changePage(currentPage + 1)"
ng-disabled="currentPage == numberOfPages - 1">
Next
</button>
</div>
<div class="form-group input-group" style="padding-left: 15px; margin-bottom:0px">
<div class="input-group-addon">Jump to:</div>
<select class="form-control"
style="max-width: 70px"
ng-model="currentPage"
ng-change="changePage(currentPage)"
ng-options="n+1 for n in [] | range:0:numberOfPages">
</select>
</div>
</td>
</tr>
<tr>
<td colspan="{{columns.length}}" style="border-top: none; padding: 0 10px">
<ul class="pagination pagination-sm" style="margin: 2px 0">
<li style="float: left; padding: 6px 12px 6px 0; color: #333333;">Results per page:</li>
<li ng-repeat="size in pageSizes" ng-if="size < data.length" ng-class="{active: pageSize == size}">
<a ng-click="changePageSize(size)"
ng-bind="size"></a>
</li>
<li ng-class="{active: pageSize >= data.length}">
<a ng-click="changePageSize(data.length)">
All ({{data.length}})
</a>
</li>
</ul>
</td>
</tr>
</tfoot>
</table>
angular.module('app.directives', [])
.directive('tableSortable', ['$timeout', function($timeout) {
return {
restrict: 'E',
transclude: true,
templateUrl: 'tableSortable.html',
scope: {
columns: '=',
data: '=',
sort: '='
},
link: function(scope, element, attrs) {
scope.selectedClass = function(columnName) {
return columnName == scope.sort.column ? 'sort-' + scope.sort.descending : false;
};
scope.changeSorting = function(columnName) {
var sort = scope.sort;
if (sort.column == columnName) {
sort.descending = !sort.descending;
} else {
sort.column = columnName;
sort.descending = false;
}
};
scope.getFilterOfColumn = function(columnName) {
for (var i = 0; i < scope.columns.length; i++) {
if (columnName == scope.columns[i].variable)
return scope.columns[i].filter;
}
return '';
};
scope.pageSizes = [1, 5, 10, 25, 50];
scope.pageSize = scope.pageSize ? parseInt(scope.pageSize) : 5;
scope.changePageSize = function(newSize) {
scope.pageSize = parseInt(newSize);
};
scope.currentPage = 0;
scope.numberOfPages = Math.ceil(scope.data.length / scope.pageSize);
scope.changePage = function(newPage) {
scope.currentPage = newPage;
};
scope.$watch('pageSize', function() {
//Recalculate number of pages
scope.numberOfPages = Math.ceil(scope.data.length / scope.pageSize);
//If page doesn't exist set to last page
if (scope.currentPage >= scope.numberOfPages) {
scope.changePage(scope.numberOfPages - 1);
}
});
}
}
}]);
angular.module('app.filters', [])
.filter('customFilter', ['$filter', function($filter) {
return function (input, filter) {
if (input == Infinity) return null;
var digits = 2;
if (filter.indexOf(':') > -1) {
digits = parseInt(filter.split(':')[1].trim());
filter = filter.split(':')[0].trim();
}
switch(filter) {
case 'text':
return input;
case 'number':
return $filter(filter)(input, digits);
case 'percentage':
return $filter('number')(input, digits) + '%';
case 'dateTime':
return $filter('date')(input, 'MMM d, y h:mm:ss a');
default:
return input;
}
}
}])
.filter('startFrom', function () {
return function (input, start) {
if (!input || isNaN(start))
return false;
return input.slice(parseInt(start));
}
})
.filter('range', function () {
return function (input, min, max) {
min = parseInt(min); //Make string input int
max = parseInt(max);
for (var i = min; i < max; i++)
input.push(i);
return input;
};
})