Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit e55d906

Browse files
bekospkozlowski-opensource
authored andcommitted
feat(pagination): total-items & optional items-per-page API
Closes #820. BREAKING CHANGE: API has undergone some changes in order to be easier to use. * `current-page` is replaced from `page`. * Number of pages is not defined by `num-pages`, but from `total-items` & `items-per-page` instead. If `items-per-page` is missing, default is 10. * `num-pages` still exists but is just readonly. Before: <pagination num-pages="10" ...></pagination> After: <pagination total-items="100" ...></pagination>
1 parent 9af6f96 commit e55d906

File tree

6 files changed

+670
-688
lines changed

6 files changed

+670
-688
lines changed

src/pagination/docs/demo.html

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
<div ng-controller="PaginationDemoCtrl" class="well well-small">
22
<h4>Default</h4>
33

4-
<pagination num-pages="noOfPages" current-page="currentPage"></pagination>
5-
<pagination boundary-links="true" num-pages="noOfPages" current-page="currentPage" class="pagination-small" previous-text="&lsaquo;" next-text="&rsaquo;" first-text="&laquo;" last-text="&raquo;"></pagination>
6-
<pagination direction-links="false" boundary-links="true" num-pages="noOfPages" current-page="currentPage"></pagination>
7-
<pagination direction-links="false" num-pages="noOfPages" current-page="currentPage"></pagination>
4+
<pagination total-items="totalItems" page="currentPage"></pagination>
5+
<pagination boundary-links="true" total-items="totalItems" page="currentPage" class="pagination-small" previous-text="&lsaquo;" next-text="&rsaquo;" first-text="&laquo;" last-text="&raquo;"></pagination>
6+
<pagination direction-links="false" boundary-links="true" total-items="totalItems" page="currentPage"></pagination>
7+
<pagination direction-links="false" total-items="totalItems" page="currentPage" num-pages="smallnumPages"></pagination>
88

99
<button class="btn" ng-click="setPage(3)">Set current page to: 3</button>
1010
The selected page no: {{currentPage}}
1111

1212
<hr />
1313
<h4>Pager</h4>
14-
<pager num-pages="noOfPages" current-page="currentPage"></pager>
14+
<pager total-items="totalItems" page="currentPage"></pager>
1515

1616
<hr />
17-
<h4>Limit the maximimum visible page-buttons</h4>
18-
<pagination num-pages="bigNoOfPages" current-page="bigCurrentPage" max-size="maxSize" class="pagination-small" boundary-links="true"></pagination>
19-
<pagination rotate="false" num-pages="bigNoOfPages" current-page="bigCurrentPage" max-size="maxSize" class="pagination-small" boundary-links="true"></pagination>
17+
<h4>Limit the maximimum visible buttons</h4>
18+
<pagination total-items="bigTotalItems" page="bigCurrentPage" max-size="maxSize" class="pagination-small" boundary-links="true"></pagination>
19+
<pagination total-items="bigTotalItems" page="bigCurrentPage" max-size="maxSize" class="pagination-small" boundary-links="true" rotate="false" num-pages="numPages"></pagination>
20+
21+
<pre>Page: {{bigCurrentPage}} / {{numPages}}</pre>
2022
</div>

src/pagination/docs/demo.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
var PaginationDemoCtrl = function ($scope) {
2-
$scope.noOfPages = 7;
2+
$scope.totalItems = 64;
33
$scope.currentPage = 4;
44
$scope.maxSize = 5;
55

66
$scope.setPage = function (pageNo) {
77
$scope.currentPage = pageNo;
88
};
99

10-
$scope.bigNoOfPages = 18;
10+
$scope.bigTotalItems = 175;
1111
$scope.bigCurrentPage = 1;
1212
};

src/pagination/docs/readme.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,26 @@ A lightweight pagination directive that is focused on ... providing pagination &
55

66
Settings can be provided as attributes in the `<pagination>` or globally configured through the `paginationConfig`.
77

8-
* `num-pages` <i class="icon-eye-open"></i>
8+
* `page` <i class="icon-eye-open"></i>
99
:
10-
Number of total pages.
10+
Current page number. First page is 1.
1111

12-
* `current-page` <i class="icon-eye-open"></i>
12+
* `total-items` <i class="icon-eye-open"></i>
1313
:
14-
Current page number.
14+
Total number of items in all pages.
15+
16+
* `items-per-page` <i class="icon-eye-open"></i>
17+
_(Defaults: 10)_ :
18+
Maximum number of items per page. A value less than one indicates all items on one page.
1519

1620
* `max-size` <i class="icon-eye-open"></i>
1721
_(Defaults: null)_ :
1822
Limit number for pagination size.
1923

24+
* `num-pages` <small class="badge">readonly</small>
25+
:
26+
Total number of pages to display.
27+
2028
* `rotate`
2129
_(Defaults: true)_ :
2230
Whether to keep current page in the middle of the visible ones.
@@ -52,7 +60,7 @@ Settings can be provided as attributes in the `<pagination>` or globally configu
5260
### Pager Settings ###
5361

5462
Settings can be provided as attributes in the `<pager>` or globally configured through the `pagerConfig`.
55-
For `num-pages`, `current-page` and `on-select-page (page)` see pagination settings. Other settings are:
63+
For `page`, `total-items`, `items-per-page`, `num-pages` and `on-select-page (page)` see pagination settings. Other settings are:
5664

5765
* `align`
5866
_(Default: true)_ :

src/pagination/pagination.js

+107-65
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,73 @@
11
angular.module('ui.bootstrap.pagination', [])
22

3-
.controller('PaginationController', ['$scope', '$interpolate', function ($scope, $interpolate) {
3+
.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) {
4+
var self = this;
45

5-
this.currentPage = 1;
6+
this.init = function(defaultItemsPerPage) {
7+
if ($attrs.itemsPerPage) {
8+
$scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
9+
self.itemsPerPage = parseInt(value, 10);
10+
$scope.totalPages = self.calculateTotalPages();
11+
});
12+
} else {
13+
this.itemsPerPage = defaultItemsPerPage;
14+
}
15+
};
616

717
this.noPrevious = function() {
8-
return this.currentPage === 1;
18+
return this.page === 1;
919
};
1020
this.noNext = function() {
11-
return this.currentPage === $scope.numPages;
21+
return this.page === $scope.totalPages;
1222
};
1323

1424
this.isActive = function(page) {
15-
return this.currentPage === page;
25+
return this.page === page;
1626
};
1727

18-
this.reset = function() {
19-
$scope.pages = [];
20-
this.currentPage = parseInt($scope.currentPage, 10);
28+
this.calculateTotalPages = function() {
29+
return this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
30+
};
2131

22-
if ( this.currentPage > $scope.numPages ) {
23-
$scope.selectPage($scope.numPages);
24-
}
32+
this.getAttributeValue = function(attribute, defaultValue, interpolate) {
33+
return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
34+
};
35+
36+
this.render = function() {
37+
this.page = parseInt($scope.page, 10) || 1;
38+
$scope.pages = this.getPages(this.page, $scope.totalPages);
2539
};
2640

27-
var self = this;
2841
$scope.selectPage = function(page) {
29-
if ( ! self.isActive(page) && page > 0 && page <= $scope.numPages) {
30-
$scope.currentPage = page;
42+
if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) {
43+
$scope.page = page;
3144
$scope.onSelectPage({ page: page });
3245
}
3346
};
3447

35-
this.getAttributeValue = function(attribute, defaultValue, interpolate) {
36-
return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue;
37-
};
48+
$scope.$watch('totalItems', function() {
49+
$scope.totalPages = self.calculateTotalPages();
50+
});
51+
52+
$scope.$watch('totalPages', function(value) {
53+
if ( $attrs.numPages ) {
54+
$scope.numPages = value; // Readonly variable
55+
}
56+
57+
if ( self.page > value ) {
58+
$scope.selectPage(value);
59+
} else {
60+
self.render();
61+
}
62+
});
63+
64+
$scope.$watch('page', function() {
65+
self.render();
66+
});
3867
}])
3968

4069
.constant('paginationConfig', {
70+
itemsPerPage: 10,
4171
boundaryLinks: false,
4272
directionLinks: true,
4373
firstText: 'First',
@@ -47,28 +77,38 @@ angular.module('ui.bootstrap.pagination', [])
4777
rotate: true
4878
})
4979

50-
.directive('pagination', ['paginationConfig', function(config) {
80+
.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
5181
return {
5282
restrict: 'EA',
5383
scope: {
54-
numPages: '=',
55-
currentPage: '=',
56-
maxSize: '=',
57-
onSelectPage: '&'
84+
page: '=',
85+
totalItems: '=',
86+
onSelectPage:' &',
87+
numPages: '='
5888
},
5989
controller: 'PaginationController',
6090
templateUrl: 'template/pagination/pagination.html',
6191
replace: true,
6292
link: function(scope, element, attrs, paginationCtrl) {
6393

6494
// Setup configuration parameters
65-
var boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ),
66-
directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ),
67-
firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true),
68-
previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
69-
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
70-
lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true),
71-
rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate);
95+
var maxSize,
96+
boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ),
97+
directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ),
98+
firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true),
99+
previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
100+
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
101+
lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true),
102+
rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate);
103+
104+
paginationCtrl.init(config.itemsPerPage);
105+
106+
if (attrs.maxSize) {
107+
scope.$parent.$watch($parse(attrs.maxSize), function(value) {
108+
maxSize = parseInt(value, 10);
109+
paginationCtrl.render();
110+
});
111+
}
72112

73113
// Create page object used in template
74114
function makePage(number, text, isActive, isDisabled) {
@@ -80,76 +120,79 @@ angular.module('ui.bootstrap.pagination', [])
80120
};
81121
}
82122

83-
scope.$watch('numPages + currentPage + maxSize', function() {
84-
paginationCtrl.reset();
123+
paginationCtrl.getPages = function(currentPage, totalPages) {
124+
var pages = [];
85125

86126
// Default page limits
87-
var startPage = 1, endPage = scope.numPages;
88-
var isMaxSized = ( angular.isDefined(scope.maxSize) && scope.maxSize < scope.numPages );
127+
var startPage = 1, endPage = totalPages;
128+
var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages );
89129

90130
// recompute if maxSize
91131
if ( isMaxSized ) {
92132
if ( rotate ) {
93133
// Current page is displayed in the middle of the visible ones
94-
startPage = Math.max(paginationCtrl.currentPage - Math.floor(scope.maxSize/2), 1);
95-
endPage = startPage + scope.maxSize - 1;
134+
startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
135+
endPage = startPage + maxSize - 1;
96136

97137
// Adjust if limit is exceeded
98-
if (endPage > scope.numPages) {
99-
endPage = scope.numPages;
100-
startPage = endPage - scope.maxSize + 1;
138+
if (endPage > totalPages) {
139+
endPage = totalPages;
140+
startPage = endPage - maxSize + 1;
101141
}
102142
} else {
103143
// Visible pages are paginated with maxSize
104-
startPage = ((Math.ceil(paginationCtrl.currentPage / scope.maxSize) - 1) * scope.maxSize) + 1;
144+
startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
105145

106146
// Adjust last page if limit is exceeded
107-
endPage = Math.min(startPage + scope.maxSize - 1, scope.numPages);
147+
endPage = Math.min(startPage + maxSize - 1, totalPages);
108148
}
109149
}
110150

111151
// Add page number links
112152
for (var number = startPage; number <= endPage; number++) {
113153
var page = makePage(number, number, paginationCtrl.isActive(number), false);
114-
scope.pages.push(page);
154+
pages.push(page);
115155
}
116156

117157
// Add links to move between page sets
118158
if ( isMaxSized && ! rotate ) {
119159
if ( startPage > 1 ) {
120160
var previousPageSet = makePage(startPage - 1, '...', false, false);
121-
scope.pages.unshift(previousPageSet);
161+
pages.unshift(previousPageSet);
122162
}
123163

124-
if ( endPage < scope.numPages ) {
164+
if ( endPage < totalPages ) {
125165
var nextPageSet = makePage(endPage + 1, '...', false, false);
126-
scope.pages.push(nextPageSet);
166+
pages.push(nextPageSet);
127167
}
128168
}
129169

130170
// Add previous & next links
131171
if (directionLinks) {
132-
var previousPage = makePage(paginationCtrl.currentPage - 1, previousText, false, paginationCtrl.noPrevious());
133-
scope.pages.unshift(previousPage);
172+
var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
173+
pages.unshift(previousPage);
134174

135-
var nextPage = makePage(paginationCtrl.currentPage + 1, nextText, false, paginationCtrl.noNext());
136-
scope.pages.push(nextPage);
175+
var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext());
176+
pages.push(nextPage);
137177
}
138178

139179
// Add first & last links
140180
if (boundaryLinks) {
141181
var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious());
142-
scope.pages.unshift(firstPage);
182+
pages.unshift(firstPage);
143183

144-
var lastPage = makePage(scope.numPages, lastText, false, paginationCtrl.noNext());
145-
scope.pages.push(lastPage);
184+
var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext());
185+
pages.push(lastPage);
146186
}
147-
});
187+
188+
return pages;
189+
};
148190
}
149191
};
150192
}])
151193

152194
.constant('pagerConfig', {
195+
itemsPerPage: 10,
153196
previousText: '« Previous',
154197
nextText: 'Next »',
155198
align: true
@@ -159,9 +202,10 @@ angular.module('ui.bootstrap.pagination', [])
159202
return {
160203
restrict: 'EA',
161204
scope: {
162-
numPages: '=',
163-
currentPage: '=',
164-
onSelectPage: '&'
205+
page: '=',
206+
totalItems: '=',
207+
onSelectPage:' &',
208+
numPages: '='
165209
},
166210
controller: 'PaginationController',
167211
templateUrl: 'template/pagination/pager.html',
@@ -173,6 +217,8 @@ angular.module('ui.bootstrap.pagination', [])
173217
nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true),
174218
align = paginationCtrl.getAttributeValue(attrs.align, config.align);
175219

220+
paginationCtrl.init(config.itemsPerPage);
221+
176222
// Create page object used in template
177223
function makePage(number, text, isDisabled, isPrevious, isNext) {
178224
return {
@@ -184,16 +230,12 @@ angular.module('ui.bootstrap.pagination', [])
184230
};
185231
}
186232

187-
scope.$watch('numPages + currentPage', function() {
188-
paginationCtrl.reset();
189-
190-
// Add previous & next links
191-
var previousPage = makePage(paginationCtrl.currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false);
192-
scope.pages.unshift(previousPage);
193-
194-
var nextPage = makePage(paginationCtrl.currentPage + 1, nextText, paginationCtrl.noNext(), false, true);
195-
scope.pages.push(nextPage);
196-
});
233+
paginationCtrl.getPages = function(currentPage) {
234+
return [
235+
makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
236+
makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
237+
];
238+
};
197239
}
198240
};
199241
}]);

0 commit comments

Comments
 (0)