Created
October 26, 2020 22:41
-
-
Save mracette/7b54c984d67493f94f8c8c39f170d746 to your computer and use it in GitHub Desktop.
Vanilla JS improved pagination algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Calculates a fixed-length array of pagination display elements, | |
* Example return value: [1, "...", 4, 5, 6, "...", 20] | |
* | |
* Inspired by https://gist.github.com/kottenator/9d936eb3e4e3c3e02598, but re-worked to ensure | |
* that the number of display elements stays constant regardless of the current page. Thus, the | |
* algorithm mimics the behavior of https://material-ui.com/components/pagination/ | |
* | |
* @param {number} currentPage | |
* The current page. The rest of the display is oriented around this page. | |
* @param {number} totalPages | |
* The total number of pages available. | |
* @param {number} [displaySize] | |
* The number of display elements. | |
* | |
* @returns An array of length === displaySize, containing content for the pagination element. | |
*/ | |
const pagination = (currentPage, totalPages, displaySize = 7) => { | |
// do not display more than the total number of pages | |
const displaySizeAdj = Math.min(displaySize, totalPages); | |
// subtract 1 to leave room for the first and last values | |
const displaySizeHalf = Math.floor(displaySizeAdj / 2) - 1; | |
// at a minimum, we want a range of [1] | |
const range = [1]; | |
if (totalPages <= 1) { | |
return range; | |
} | |
/* | |
If currentPage is near the center of the range, it will be bounded by +/- (displaySizeHalf - 1) | |
As currentPage approaches totalPages, i needs a downward adjustment to ensure | |
range.length = displaySize | |
Example: if totalPages = 20, currentPage = 19, | |
we want a range: | |
[1, '...', 16, 17, 18, 19, 20] | |
rather than: | |
[1, '...', 17, 18, 19, 20] | |
*/ | |
let i = currentPage - displaySizeHalf; | |
i = Math.min(i, totalPages - displaySizeHalf * 2 - 1); | |
while (range.length < displaySizeAdj && i !== totalPages) { | |
if (i < totalPages && i > 1) { | |
range.push(i); | |
} | |
i++; | |
} | |
// totalPages is always the last entry | |
range[displaySizeAdj - 1] = totalPages; | |
// check for starting ellipsis | |
if (range[1] !== 2) { | |
range[1] = "..."; | |
} | |
// check for ending ellipsis | |
if (range[displaySizeAdj - 2] !== totalPages - 1) { | |
range[displaySizeAdj - 2] = "..."; | |
} | |
return range; | |
}; | |
// illustrates function output | |
const total = 20; | |
const testValues = [...Array(total + 1).keys()].slice(1); | |
for (const x in testValues) { | |
console.log( | |
`pagination(${x}, ${total}) -> ` + pagination(x, total).toString() | |
); | |
} | |
/* | |
pagination(0, 20) -> 1,2,3,4,5,...,20 | |
pagination(1, 20) -> 1,2,3,4,5,...,20 | |
pagination(2, 20) -> 1,2,3,4,5,...,20 | |
pagination(3, 20) -> 1,2,3,4,5,...,20 | |
pagination(4, 20) -> 1,2,3,4,5,...,20 | |
pagination(5, 20) -> 1,...,4,5,6,...,20 | |
pagination(6, 20) -> 1,...,5,6,7,...,20 | |
pagination(7, 20) -> 1,...,6,7,8,...,20 | |
pagination(8, 20) -> 1,...,7,8,9,...,20 | |
pagination(9, 20) -> 1,...,8,9,10,...,20 | |
pagination(10, 20) -> 1,...,9,10,11,...,20 | |
pagination(11, 20) -> 1,...,10,11,12,...,20 | |
pagination(12, 20) -> 1,...,11,12,13,...,20 | |
pagination(13, 20) -> 1,...,12,13,14,...,20 | |
pagination(14, 20) -> 1,...,13,14,15,...,20 | |
pagination(15, 20) -> 1,...,14,15,16,...,20 | |
pagination(16, 20) -> 1,...,15,16,17,...,20 | |
pagination(17, 20) -> 1,...,16,17,18,19,20 | |
pagination(18, 20) -> 1,...,16,17,18,19,20 | |
pagination(19, 20) -> 1,...,16,17,18,19,20 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello. :)
I'm trying this and the output is not consistent. The ellipsis must not be part of
displaySize
. If I setdisplaySize
to7
, the output is1,...,4,5,6,...,20
, but it should be1,...,3,4,5,6,7,...,20
. Your solution is very fast, can you fix it, please?