var app = angular.module('plunker', ['xui.table','ngMaterial']);
app.constant('TableHeader', [{
header: 'id',
title: 'id',
sortable: true
}, {
header: 'name',
title: 'name',
sortable: true
}, {
header: 'description',
title: 'description',
sortable: true
}, {
header: 'field3',
title: 'field3',
sortable: true
}, {
header: 'field4',
title: 'field4',
sortable: true
}, {
header: 'Action',
title: 'Action',
sortable: false
}
]);
app.controller('MainCtrl', function($scope, TableHeader) {
$scope.name = 'World';
$scope.TableHeader = TableHeader;
$scope.List = [];
for (var i = 1; i < 65; i++) {
$scope.List.push({
"id": "0" + i,
"name": "name " + i,
"description": "description " + i,
"field3": "field3 " + i,
"field4": true,
"field5 ": "field5 " + i
});
}
$scope.search = {};
$scope.searchfn = function(input) {
if ( !! input) {
var tmp = false;
angular.forEach($scope.search, function(val, key) {
if ( !! (input[key].indexOf(val || '') !== -1)) {
tmp = true;
}
});
return tmp;
}
};
$scope.open = function(input) {
alert(input);
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link data-require="angular-material.min.css" rel="Stylesheet" href="https://rawgit.com/angular/bower-material/v0.7.0-rc2-master-d6311e8/angular-material.min.css" data-semver="v0.7.0-rc2-master-d6311e8" />
<link rel="stylesheet" href="style.css" />
<link data-require="bootstrap-css" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" data-semver="3.3.1" />
<script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.8/angular.js" data-semver="1.3.8"></script>
<script src="pagination.js"></script>
<script src="xuiTable.js"></script>
<script data-require="hammer.js@2.0.x" src="https://rawgit.com/hammerjs/hammer.js/2.0.4/hammer.min.js" data-semver="2.0.4"></script>
<script data-require="angular-material.min.js@v0.7.0-rc2-master-d6311e8" src="https://rawgit.com/angular/bower-material/v0.7.0-rc2-master-d6311e8/angular-material.min.js" data-semver="v0.7.0-rc2-master-d6311e8"></script>
<script data-require="angular-aria.min.js@1.3.8" src="https://rawgit.com/angular/bower-angular-aria/v1.3.8/angular-aria.min.js" data-semver="1.3.8"></script>
<script data-require="angular-animate.min.js@1.3.8" src="https://rawgit.com/angular/bower-angular-animate/v1.3.8/angular-animate.min.js" data-semver="1.3.8"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div>
<a href="https://github.com/maxisam/Angular-XUI/tree/master/xuiTable">GitHub</a>
</div>
<input type="text" ng-model="PageSize" placeholder="page size" />
<input type="text" ng-model="search.id" placeholder="id" />
<input type="text" ng-model="search.description" placeholder="description" />
<table xui-table="test" table-headers="TableHeader" table-data="List" items-per-page="10" page-window="PageSize" table-pager="true" table-filter="searchfn(input)" table-filter-factor="search">
<tbody>
<tr>
<td class="id" data-fileid="{{row.id}}">{{row.id}} </td>
<td class="name">{{row.name }} </td>
<td class="description">{{row.description}} </td>
<td class="field3">{{row.field3}} </td>
<td class="field4">
<md-checkbox class="field4" ng-model="row.field4" aria-label="Selected"></md-checkbox>
</td>
<td class="Action">
<button ng-click="$parent.$parent.open(row.id)">test</button>
</td>
</tr>
</tbody>
</table>
</body>
</html>
/* Put your css in here */
.sort-true {
padding-right: 14px;
background: no-repeat right center url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAICAYAAAAvOAWIAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAX0lEQVQoU32NQQrAMAgEBa+CvfX5PYa+pn/oR2w2xLIQibAgOqMSEYe73wh6oVp2Ztb6PhAWEszd5OTJAQknRJ73Hpz4bMZ1RFXfAgQ3ahEIxsUf3AklWAlbkIWrev0BT3ZAxrSn1UcAAAAASUVORK5CYII=')
/*../Icons/Icon-down-white.png*/
}
.sort-false {
padding-right: 14px;
background: no-repeat right center url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAICAYAAAAvOAWIAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAXklEQVQoU2NgwAT8QKH5QAyi8QKQgvNA/B9K49SArBCkGKcGbAqxasBQyMzM/AhqMoYGmBvBEvz8/Cv///8vDqIxNPDw8CyHCUIVCoCCAKhBAFkDWB1MEFkhLLzQ5QBl6UDG/jPuNgAAAABJRU5ErkJggg==')
/*../Icons/Icon-up-white.png*/
}
.NoData td.NoData {
text-align: center;
}
.even {
background-color: #aaa
}
.odd {
background-color: #fff;
}
.icon {
max-height: 20px;
max-width: 20px;
}
.SelectedRow {
background-color: #888;
}
/**
* Created by linsz on 3/14/14.
*/
angular.module('xui.table', ['ui.bootstrap.pagination'])
.controller('xuiTableCtrl', ['$scope', '$attrs', 'orderByFilter', '$filter', '$parse',
function($scope, $attrs, orderByFilter, $filter, $parse) {
var attrs = ['tableHeaders', 'tableData', 'itemsPerPage', 'pageWindow', 'tableFilterFactor'];
angular.forEach(attrs, function(val) {
var tmp = $parse($attrs[val]);
$scope[val] = tmp($scope.$parent);
$scope.$parent.$watch(tmp, function(newVal) {
$scope[val] = tmp($scope.$parent);
});
});
$attrs.$observe('tablePager', function(val) {
$scope.tablePager = val;
});
$scope.tableFilter = function(locals) {
return $parse($attrs.tableFilter)($scope.$parent, locals);
};
var that = this;
$scope.Page = {
current: 1
};
$scope.sort = {
column: '',
descending: false
};
$scope.SelectedCol = function(column) {
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
};
$scope.ChangeSorting = function(column) {
if ($scope.sort.column == column) {
$scope.sort.descending = !$scope.sort.descending;
} else {
$scope.sort.column = column.toString();
$scope.sort.descending = false;
}
$scope.tableDataFiltered = orderByFilter($scope.tableDataFiltered, $scope.sort.column, $scope.sort.descending);
that.pagination();
};
this.pagination = function() {
$scope.pagedItems = [];
if ( !! $scope.tablePager && angular.lowercase($scope.tablePager) === 'true') {
for (var i = 0; i < $scope.tableDataFiltered.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [$scope.tableDataFiltered[i]];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.tableDataFiltered[i]);
}
}
} else {
$scope.pagedItems[0] = $scope.tableDataFiltered;
}
};
this.search = function() {
if ( !! $scope.tableFilterFactor && !angular.equals($scope.tableFilterFactor, {}) && !! $scope.tableFilter) {
$scope.tableDataFiltered = $filter('filter')($scope.tableData, function(input) {
return $scope.tableFilter({
input: input
});
});
} else {
$scope.tableDataFiltered = $scope.tableData;
}
that.pagination();
};
this.search();
$scope.$watch('tableFilterFactor', function(newVal) {
that.search();
}, true);
}
])
.directive('xuiTable', ['$compile',
function($compile) {
return {
scope: true,
replace: true,
transclude: true,
templateUrl: 'xuiTable.html',
controller: 'xuiTableCtrl',
link: function(scope, elm, attrs, controller, transcludeFn) {
if ( !! scope.tableDataFiltered.length) {
var tbody = transcludeFn(scope, function(clone) {
clone.children('tr').attr("ng-repeat", 'row in pagedItems[Page.current-1]');
});
$compile(tbody)(scope, function(clone) {
elm.addClass(attrs.xuiTable).append(clone);
});
}
}
};
}
]);
<table class="table table-striped">
<thead>
<tr>
<th class="{{header.header}}" data-ng-repeat="header in tableHeaders">
<a data-ng-if="header.sortable" href='javascript:void(0)' data-ng-click="ChangeSorting(header.header)" data-ng-class="SelectedCol(header.header)">{{header.title}}</a>
<span class="{{header.header}}" data-ng-if="!header.sortable">{{header.title}}</span>
</th>
</tr>
</thead>
<tbody data-ng-if="!tableDataFiltered.length">
<tr>
<td class="{{header.header}}" data-ng-repeat="header in tableHeaders">N/A</td>
</tr>
</tbody>
<tfoot data-ng-if="!!tablePager">
<td colspan="{{tableHeaders.length}}">
<div class="pagination pull-right">
<pagination total-items="tableDataFiltered.length" page="Page.current" max-size="pageWindow" class="pagination-sm" boundary-links="true"></pagination>
</div>
</td>
</tfoot>
</table>
angular.module('ui.bootstrap.pagination', [])
.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate',
function ($scope, $attrs, $parse, $interpolate) {
var self = this,
setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
this.init = function (defaultItemsPerPage) {
if ($attrs.itemsPerPage) {
$scope.$parent.$watch($parse($attrs.itemsPerPage), function (value) {
self.itemsPerPage = parseInt(value, 10);
$scope.totalPages = self.calculateTotalPages();
});
} else {
this.itemsPerPage = defaultItemsPerPage;
}
};
this.noPrevious = function () {
return this.page === 1;
};
this.noNext = function () {
return this.page === $scope.totalPages;
};
this.isActive = function (page) {
return this.page === page;
};
this.calculateTotalPages = function () {
var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
return Math.max(totalPages || 0, 1);
};
this.getAttributeValue = function (attribute, defaultValue, interpolate) {
return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
};
this.render = function () {
this.page = parseInt($scope.page, 10) || 1;
if (this.page > 0 && this.page <= $scope.totalPages) {
$scope.pages = this.getPages(this.page, $scope.totalPages);
}
};
$scope.selectPage = function (page) {
if (!self.isActive(page) && page > 0 && page <= $scope.totalPages) {
$scope.page = page;
$scope.onSelectPage({
page: page
});
}
};
$scope.$watch('page', function () {
self.render();
});
$scope.$watch('totalItems', function () {
$scope.totalPages = self.calculateTotalPages();
});
$scope.$watch('totalPages', function (value) {
setNumPages($scope.$parent, value); // Readonly variable
if (self.page > value) {
$scope.selectPage(value);
} else {
self.render();
}
});
}
])
.constant('paginationConfig', {
itemsPerPage: 10,
boundaryLinks: false,
directionLinks: true,
firstText: 'First',
previousText: 'Previous',
nextText: 'Next',
lastText: 'Last',
rotate: true
})
.directive('pagination', ['$parse', 'paginationConfig',
function ($parse, config) {
return {
restrict: 'EA',
scope: {
page: '=',
totalItems: '=',
onSelectPage: ' &'
},
controller: 'PaginationController',
templateUrl: 'pagination.html',
replace: true,
link: function (scope, element, attrs, paginationCtrl) {
// Setup configuration parameters
var maxSize,
boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks),
directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks),
firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true),
previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true),
rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate);
paginationCtrl.init(config.itemsPerPage);
if (attrs.maxSize) {
scope.$parent.$watch($parse(attrs.maxSize), function (value) {
maxSize = parseInt(value, 10);
paginationCtrl.render();
});
}
// Create page object used in template
function makePage(number, text, isActive, isDisabled) {
return {
number: number,
text: text,
active: isActive,
disabled: isDisabled
};
}
paginationCtrl.getPages = function (currentPage, totalPages) {
var pages = [];
// Default page limits
var startPage = 1,
endPage = totalPages;
var isMaxSized = (angular.isDefined(maxSize) && maxSize < totalPages);
// recompute if maxSize
if (isMaxSized) {
if (rotate) {
// Current page is displayed in the middle of the visible ones
startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
endPage = startPage + maxSize - 1;
// Adjust if limit is exceeded
if (endPage > totalPages) {
endPage = totalPages;
startPage = endPage - maxSize + 1;
}
} else {
// Visible pages are paginated with maxSize
startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
// Adjust last page if limit is exceeded
endPage = Math.min(startPage + maxSize - 1, totalPages);
}
}
// Add page number links
for (var number = startPage; number <= endPage; number++) {
var page = makePage(number, number, paginationCtrl.isActive(number), false);
pages.push(page);
}
// Add links to move between page sets
if (isMaxSized && !rotate) {
if (startPage > 1) {
var previousPageSet = makePage(startPage - 1, '...', false, false);
pages.unshift(previousPageSet);
}
if (endPage < totalPages) {
var nextPageSet = makePage(endPage + 1, '...', false, false);
pages.push(nextPageSet);
}
}
// Add previous & next links
if (directionLinks) {
var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
pages.unshift(previousPage);
var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext());
pages.push(nextPage);
}
// Add first & last links
if (boundaryLinks) {
var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious());
pages.unshift(firstPage);
var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext());
pages.push(lastPage);
}
return pages;
};
}
};
}
])
.constant('pagerConfig', {
itemsPerPage: 10,
previousText: '« Previous',
nextText: 'Next »',
align: true
})
.directive('pager', ['pagerConfig',
function (config) {
return {
restrict: 'EA',
scope: {
page: '=',
totalItems: '=',
onSelectPage: ' &'
},
controller: 'PaginationController',
templateUrl: 'template/pagination/pager.html',
replace: true,
link: function (scope, element, attrs, paginationCtrl) {
// Setup configuration parameters
var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
align = paginationCtrl.getAttributeValue(attrs.align, config.align);
paginationCtrl.init(config.itemsPerPage);
// Create page object used in template
function makePage(number, text, isDisabled, isPrevious, isNext) {
return {
number: number,
text: text,
disabled: isDisabled,
previous: (align && isPrevious),
next: (align && isNext)
};
}
paginationCtrl.getPages = function (currentPage) {
return [
makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
];
};
}
};
}
]);
<ul class="pagination">
<li ng-repeat="page in pages" ng-class="{active: page.active, disabled: page.disabled}"><a ng-click="selectPage(page.number)">{{page.text}}</a></li>
</ul>