angular-minimal-grid
Version:
Implementation of data grid using twitter bootstrap for angularjs applications.
277 lines (234 loc) • 9.86 kB
JavaScript
(function () {
angular.module('ngMinimalGrid', [])
.provider('minimalGridConfig',function(){
this.statsMessage = 'Showing %1 to %2 of %3 results'
this.setStatsMessage = function(message){
this.statsMessage = message
return this
}
this.firstButtonLabel = 'First'
this.setFirstLabel = function(label){
this.firstButtonLabel = label
return this
}
this.lastButtonLabel = 'Last'
this.setLastLabel = function(label){
this.lastButtonLabel = label
return this
}
this.$get = function(){
return this
}
})
.controller('minimalGridCtrl', ['$scope', '$parse', '$filter', 'minimalGridConfig', '$sce', function($scope, $parse, $filter, minimalGridConfig, $sce){
$scope.firstButtonLabel = minimalGridConfig.firstButtonLabel
$scope.lastButtonLabel = minimalGridConfig.lastButtonLabel
// model
if (!angular.isArray($scope.rows)){
throw new Error('minimalGrid error: rows must be an Array')
}
$scope.$watchCollection('rows', function (newRows) {
setData(newRows)
if (!$scope.fake) {
updatePagesTotal($scope.data.length)
updatePages()
if ($scope._lastColumnOrderBy) $scope.changeOrderBy($scope._lastColumnOrderBy)
if ($scope._lastPagePaginate) $scope.changePaginate($scope._lastPagePaginate)
}
})
if ($scope.fake || $scope.totalRows) {
$scope.$watch('totalRows', function (newTotal) {
$scope._lastTotalPopulatePages = newTotal
updatePagesTotal(newTotal)
updatePages()
})
}
// local binds
$scope.columnParse = function (assign, obj, columns) {
var getter = $parse(assign)
var value = getter(obj)
if (columns.formatDate) {
value = $filter('date')(value * 1000, columns.formatDate, '+0000')
}
if (!!columns.onRender){
return $sce.trustAsHtml( columns.onRender(value).toString() )
}else{
return value
}
}
$scope.statsParse = function () {
var message = minimalGridConfig.statsMessage
var first = (($scope.pages.current - 1) * $scope.pages.max) > 0 ? (($scope.pages.current - 1) * $scope.pages.max) + 1 : ($scope._data.length > 0) ? 1 : 0;
if (!$scope.fake) {
var last = ((($scope.pages.current - 1) * $scope.pages.max) + $scope.pages.max) < $scope._data.length ? ((($scope.pages.current - 1) * $scope.pages.max) + $scope.pages.max) : $scope._data.length
var total = $scope._data.length
} else {
if ($scope._lastTotalPopulatePages != undefined) {
var last = ((($scope.pages.current - 1) * $scope.pages.max) + $scope.pages.max) < $scope._lastTotalPopulatePages ? ((($scope.pages.current - 1) * $scope.pages.max) + $scope.pages.max) : $scope._lastTotalPopulatePages
var total = $scope._lastTotalPopulatePages
} else {
var last = 0
var total = 0
}
}
return message.replace('%1', first).replace('%2', last).replace('%3', total)
}
$scope.changeOrderBy = function (column) {
if ($scope._lastColumnOrderBy != column) {
var classes = column.class
$scope.columns.map(function (val) {
val.class = 'sorting'
})
column.class = (classes == 'sorting_asc') ? 'sorting_desc' : 'sorting_asc'
$scope._lastColumnOrderBy = Object.assign({}, column)
}
if (!$scope.fake) {
if ($scope.pages.current != 1) {
$scope.pages.current = 1
setData($scope._data)
updatePages()
}
var data = $filter('orderBy')($scope.data, column.key, (column.class == 'sorting_desc'))
setData(data)
}
if (angular.isDefined($scope.changeOrderByCallback)) {
if (!angular.isFunction($scope.changeOrderByCallback)){
throw new Error('minimalGrid error: on-change-order-by must be a Function')
}
$scope.changeOrderByCallback({
orderBy: {
orderdirection: column.class.replace('sorting_', ''),
orderby: column.key
}
})
}
}
$scope.changePaginate = function (page) {
$scope._lastPagePaginate = Number(page)
$scope.pages.current = page
updatePages()
if (!$scope.fake) {
setData($scope._data)
var cut = ($scope.pages.current - 1) > 0 ? ($scope.pages.current - 1) * $scope.pages.max : 0
$scope.data = $scope.data.slice(cut)
}
if ($scope.changePaginateCallback) {
$scope.changePaginateCallback({ pages: $scope.pages })
}
}
$scope.clickRow = function (row) {
if ($scope.clickRowCallback) {
$scope.clickRowCallback({ row: row })
}
}
// local functions
function updatePagesTotal(totalItems) {
$scope.pages.total = []
var totalPages = Math.ceil(totalItems / $scope.pages.max)
for (var x = 1; x <= totalPages; x++) $scope.pages.total.push(x)
}
function updatePages() {
if ($scope.pages.current > $scope.pages.total.length) {
$scope.pages.current = 1
$scope._lastPagePaginate = 1
}
$scope.pages.first = 1
$scope.pages.last = $scope.pages.total.length
$scope.pages.previous = (($scope.pages.current - 1) > 0) ? ($scope.pages.current - 1) : 1
$scope.pages.next = (($scope.pages.current + 1) <= $scope.pages.total.length) ? ($scope.pages.current + 1) : $scope.pages.total.length
$scope.pages.pagination = getPagination()
}
function getPagination() {
var pagination = 0
if (pagination < $scope.pages.range) pagination = $scope.pages.current - Math.ceil($scope.pages.range/2)
var diffTotalRange = ($scope.pages.total.length - $scope.pages.range)
if (pagination > diffTotalRange) pagination = diffTotalRange
if (pagination < 0) pagination = 0
return pagination
}
function setData(data) {
$scope._data = data
$scope.data = Object.assign([], $scope._data)
}
$scope._data = []
$scope.data = []
$scope._lastColumnOrderBy = undefined
$scope._lastPagePaginate = undefined
$scope._lastTotalPopulatePages = undefined
// behavior control
$scope.fake = $scope.fake || false
// column control
if (!angular.isArray($scope.columns)){
throw new Error('minimalGrid error: columns must be an Array')
}
$scope.columns.map(function (val) {
val.class = 'sorting'
})
if (angular.isDefined($scope.paginationMax) && !angular.isNumber($scope.paginationMax)){
throw new Error('minimalGrid error: pagination-max must be a Number')
}
if (angular.isDefined($scope.paginationRange) && !angular.isNumber($scope.paginationRange)){
throw new Error('minimalGrid error: pagination-range must be a Number')
}
$scope.pages = {
first: 1,
last: 1,
previous: 1,
next: 1,
current: 1,
total: [1],
max: $scope.paginationMax || 10,
range: $scope.paginationRange || 5,
pagination: 0
}
}])
.directive('minimalGrid', [function(){
return {
restrict: 'E',
scope: {
columns: '<',
rows: '<',
fake: '<?',
totalRows: '<?',
paginationMax: '<?',
paginationRange: '<?',
changeOrderByCallback: '&?onChangeOrderBy',
changePaginateCallback: '&?onChangePaginate',
clickRowCallback: '&?onClickRow'
},
controller:'minimalGridCtrl',
template:
'<div ng-bind="statsParse()"></div>' +
' <table class="dataTable table table-striped table-bordered table-hover no-footer">' +
' <thead>' +
' <tr>' +
' <th ng-click="changeOrderBy(column)" ng-repeat="column in columns" class="{{ column.class }} {{ column.hide }}">{{ column.title }}</th>' +
' </tr>' +
' </thead>' +
' <tbody>' +
' <tr class="odd" ng-repeat="dataRow in data | limitTo : pages.max">' +
' <td ng-click="clickRow(dataRow)" ng-repeat="column in columns" class="{{ columns[$index].hide }}">' +
' <span ng-if="!!columns[$index].onRender" ng-bind-html="columnParse(columns[$index].key, dataRow, columns[$index])"></span>' +
' <span ng-if="!!!columns[$index].onRender" ng-bind="columnParse(columns[$index].key, dataRow, columns[$index])"></span>' +
' </td>' +
' </tr>' +
' </tbody>' +
' </table>' +
' <div class="pull-right">' +
' <ul class="pagination">' +
' <li><a href="#" ng-click="changePaginate(pages.first)">{{ firstButtonLabel }}</a></li>' +
' <li>' +
' <a href="#" ng-click="changePaginate(pages.previous)">' +
' << </a>' +
' </li>' +
' <li class="{{ ( n == pages.current ? \'active\' : \'\') }}"' +
' ng-click="changePaginate(n)" ng-repeat="n in pages.total | limitTo : pages.range : pages.pagination"><a href="#">{{ n }}</a></li>' +
' <li><a href="#" ng-click="changePaginate(pages.next)"> >> </a></li>' +
' <li><a href="#" ng-click="changePaginate(pages.last)">{{ lastButtonLabel }}</a></li>' +
' </ul>' +
' </div>' +
'</div>' +
'<div class="clearfix"></div>'
}
}])
})();