Skip to content

Commit ae8ce78

Browse files
authored
feat(b-pagination): if number of pages changes, try and keep current page active (closes #3716) (#3990)
1 parent 253b4f6 commit ae8ce78

File tree

2 files changed

+111
-24
lines changed

2 files changed

+111
-24
lines changed

src/components/pagination/pagination.js

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
11
import Vue from '../../utils/vue'
22
import { getComponentConfig } from '../../utils/config'
33
import { isVisible } from '../../utils/dom'
4+
import { isUndefinedOrNull } from '../../utils/inspect'
45
import paginationMixin from '../../mixins/pagination'
56

7+
// --- Constants ---
8+
69
const NAME = 'BPagination'
710

811
const DEFAULT_PER_PAGE = 20
912
const DEFAULT_TOTAL_ROWS = 0
1013

11-
// Sanitize the provided per page number (converting to a number)
12-
const sanitizePerPage = val => {
13-
const perPage = parseInt(val, 10) || DEFAULT_PER_PAGE
14-
return perPage < 1 ? 1 : perPage
15-
}
16-
17-
// Sanitize the provided total rows number (converting to a number)
18-
const sanitizeTotalRows = val => {
19-
const totalRows = parseInt(val, 10) || DEFAULT_TOTAL_ROWS
20-
return totalRows < 0 ? 0 : totalRows
21-
}
22-
2314
const props = {
2415
size: {
2516
type: String,
@@ -39,7 +30,21 @@ const props = {
3930
}
4031
}
4132

42-
// The render function is brought in via the pagination mixin
33+
// --- Helper functions ---
34+
35+
// Sanitize the provided per page number (converting to a number)
36+
const sanitizePerPage = val => {
37+
const perPage = parseInt(val, 10) || DEFAULT_PER_PAGE
38+
return perPage < 1 ? 1 : perPage
39+
}
40+
41+
// Sanitize the provided total rows number (converting to a number)
42+
const sanitizeTotalRows = val => {
43+
const totalRows = parseInt(val, 10) || DEFAULT_TOTAL_ROWS
44+
return totalRows < 0 ? 0 : totalRows
45+
}
46+
47+
// The render function is brought in via the `paginationMixin`
4348
// @vue/component
4449
export const BPagination = /*#__PURE__*/ Vue.extend({
4550
name: NAME,
@@ -49,16 +54,32 @@ export const BPagination = /*#__PURE__*/ Vue.extend({
4954
numberOfPages() {
5055
const result = Math.ceil(sanitizeTotalRows(this.totalRows) / sanitizePerPage(this.perPage))
5156
return result < 1 ? 1 : result
57+
},
58+
pageSizeNumberOfPages() {
59+
// Used for watching changes to `perPage` and `numberOfPages`
60+
return {
61+
perPage: sanitizePerPage(this.perPage),
62+
totalRows: sanitizeTotalRows(this.totalRows),
63+
numberOfPages: this.numberOfPages
64+
}
5265
}
5366
},
5467
watch: {
55-
numberOfPages(newVal) {
56-
if (newVal === this.localNumberOfPages) {
57-
/* istanbul ignore next */
58-
return
68+
pageSizeNumberOfPages(newVal, oldVal) {
69+
if (!isUndefinedOrNull(oldVal)) {
70+
if (newVal.perPage !== oldVal.perPage && newVal.totalRows === oldVal.totalRows) {
71+
// If the page size changes, reset to page 1
72+
this.currentPage = 1
73+
} else if (
74+
newVal.numberOfPages !== oldVal.numberOfPages &&
75+
this.currentPage > newVal.numberOfPages
76+
) {
77+
// If `numberOfPages` changes and is less than
78+
// the `currentPage` number, reset to page 1
79+
this.currentPage = 1
80+
}
5981
}
60-
this.localNumberOfPages = newVal
61-
this.currentPage = 1
82+
this.localNumberOfPages = newVal.numberOfPages
6283
}
6384
},
6485
created() {

src/components/pagination/pagination.spec.js

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,15 @@ describe('pagination', () => {
150150
wrapper.setProps({
151151
totalRows: 4
152152
})
153+
await waitNT(wrapper.vm)
153154

154155
expect(wrapper.is('ul')).toBe(true)
155156
expect(wrapper.findAll('li').length).toBe(8)
156157

157158
wrapper.setProps({
158159
perPage: 2
159160
})
161+
await waitNT(wrapper.vm)
160162

161163
expect(wrapper.is('ul')).toBe(true)
162164
expect(wrapper.findAll('li').length).toBe(6)
@@ -679,8 +681,8 @@ describe('pagination', () => {
679681
wrapper.destroy()
680682
})
681683

682-
it('changing the pagesize resets to page 1', async () => {
683-
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2987
684+
it('changing the number of pages to less than current page number resets to page 1', async () => {
685+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3716
684686
const wrapper = mount(BPagination, {
685687
propsData: {
686688
totalRows: 10,
@@ -694,16 +696,79 @@ describe('pagination', () => {
694696
expect(wrapper.vm.currentPage).toBe(10)
695697
expect(wrapper.emitted('input')).not.toBeDefined()
696698

699+
// Change total rows to larger value. Should not change page number
700+
wrapper.setProps({
701+
totalRows: 20
702+
})
703+
await waitNT(wrapper.vm)
704+
expect(wrapper.vm.currentPage).toBe(10)
705+
expect(wrapper.emitted('input')).not.toBeDefined()
706+
707+
// Change to page 20
708+
wrapper.setProps({
709+
value: 20
710+
})
711+
await waitNT(wrapper.vm)
712+
expect(wrapper.vm.currentPage).toBe(20)
713+
expect(wrapper.emitted('input')).toBeDefined()
714+
expect(wrapper.emitted('input').length).toBe(1)
715+
expect(wrapper.emitted('input')[0][0]).toBe(20)
716+
717+
// Decrease number of pages should reset to page 1
718+
wrapper.setProps({
719+
totalRows: 10
720+
})
721+
await waitNT(wrapper.vm)
722+
expect(wrapper.vm.currentPage).toBe(1)
723+
expect(wrapper.emitted('input').length).toBe(2)
724+
expect(wrapper.emitted('input')[1][0]).toBe(1)
725+
726+
// Change to page 3
727+
wrapper.setProps({
728+
value: 3
729+
})
730+
await waitNT(wrapper.vm)
731+
expect(wrapper.vm.currentPage).toBe(3)
732+
expect(wrapper.emitted('input').length).toBe(3)
733+
expect(wrapper.emitted('input')[2][0]).toBe(3)
734+
735+
// Decrease number of pages to 5 should not reset to page 1
736+
wrapper.setProps({
737+
totalRows: 5
738+
})
739+
await waitNT(wrapper.vm)
740+
expect(wrapper.vm.currentPage).toBe(3)
741+
expect(wrapper.emitted('input').length).toBe(3)
742+
743+
wrapper.destroy()
744+
})
745+
746+
it('changing per-page resets to page 1', async () => {
747+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2987
748+
const wrapper = mount(BPagination, {
749+
propsData: {
750+
totalRows: 10,
751+
perPage: 1,
752+
value: 4,
753+
limit: 20
754+
}
755+
})
756+
expect(wrapper.isVueInstance()).toBe(true)
757+
758+
expect(wrapper.vm.currentPage).toBe(4)
759+
expect(wrapper.emitted('input')).not.toBeDefined()
760+
761+
// Change perPage
697762
wrapper.setProps({
698-
perPage: 3
763+
perPage: 2
699764
})
700765
await waitNT(wrapper.vm)
701766
expect(wrapper.vm.currentPage).toBe(1)
702767
expect(wrapper.emitted('input')).toBeDefined()
703768
expect(wrapper.emitted('input').length).toBe(1)
704769
expect(wrapper.emitted('input')[0][0]).toBe(1)
705770

706-
// Change to page 3
771+
// Change page to 3
707772
wrapper.setProps({
708773
value: 3
709774
})
@@ -712,7 +777,8 @@ describe('pagination', () => {
712777
expect(wrapper.emitted('input').length).toBe(2)
713778
expect(wrapper.emitted('input')[1][0]).toBe(3)
714779

715-
// Increasing number of pages should reset to page 1
780+
// Change perPage. Should reset to page 1, even though
781+
// current page is within range of numberOfPages
716782
wrapper.setProps({
717783
perPage: 1
718784
})

0 commit comments

Comments
 (0)