<section class='app-container'>
<ul class='list'>
</ul>
<div class='pagination__wrapper'>
<section class='pagination__items'>
<button class='pagination__navigate-btn' onclick='firstPage()'>First</button>
<button class='pagination__navigate-btn' onclick='prevPage()'>Prev</button>
<ul class='pagination__pages'>
</ul>
<button class='pagination__navigate-btn' onclick='nextPage()'>Next</button>
<button class='pagination__navigate-btn' onclick='lastPage()'>Last</button>
</section>
</div>
</section>
.pagination__pages {
display: inline-flex;
list-style-type: none;
padding: 0;
}
.pagination__page-btn{
border:1px solid black;
}
.pagination__navigate-btn {
border:1px solid black;
}
.pagination__page-btn--active {
border:1px solid black;
background: #a3a3ff;
}
.list {
list-style-type: none;
padding: 0;
}
.app-container{
display:flex;
flex-direction:column;
align-items:center;
}
// Records to paginate on
const records = [
...Array(346)
.fill("")
.map((val, index) => `Name-${val - index}`)
];
// Paginator Class
class Paginator {
#recordsPerPage;
#totalRecords;
#noOfPages;
#visiblePages;
#activePage;
#visiblePagesEndRange;
constructor(totalRecords, recordsPerPage = 1, visiblePages = 1) {
this.#recordsPerPage = recordsPerPage;
this.#totalRecords = totalRecords;
this.#noOfPages = Math.ceil(this.#totalRecords / this.#recordsPerPage);
this.#visiblePages = visiblePages;
this.#activePage = 1;
this.#visiblePagesEndRange = visiblePages;
// below validations can be improved and really not necessary for bare minimum pagination but 🤷♂️
this.#validate();
}
#validate() {
if (this.#recordsPerPage <= 0) {
this.#recordsPerPage = 1;
}
if (this.#visiblePages <= 0) {
this.#visiblePages = 1;
}
if(this.#totalRecords<=0){
this.#totalRecords = 1;
}
if (this.#noOfPages <= 0) {
this.#noOfPages = Math.ceil(this.#totalRecords / this.#recordsPerPage);
}
if (this.#visiblePagesEndRange <= 0) {
this.#visiblePagesEndRange = this.#visiblePages;
}
if (this.#visiblePages > this.#noOfPages) {
this.#visiblePages = this.#noOfPages;
this.#visiblePagesEndRange = this.#visiblePages;
}
if (this.#recordsPerPage > this.#totalRecords) {
this.#recordsPerPage = this.#totalRecords;
}
}
getActivePage(){
return this.#activePage;
}
gotoNextPage() {
if (this.#activePage < this.#noOfPages) {
this.#activePage += 1;
if (this.#activePage > this.#visiblePagesEndRange) {
this.#visiblePagesEndRange += this.#visiblePages;
this.#visiblePagesEndRange = Math.min(this.#visiblePagesEndRange, this.#noOfPages);
}
}
}
gotoPrevPage() {
if (this.#activePage > 1) {
this.#activePage -= 1;
if (this.#activePage % this.#visiblePages === 0) {
this.#visiblePagesEndRange = this.#activePage;
}
}
}
gotoFirstPage() {
this.#activePage = 1;
this.#visiblePagesEndRange = this.#visiblePages;
}
gotoLastPage() {
this.#activePage = this.#noOfPages;
this.#visiblePagesEndRange = this.#noOfPages;
}
gotoPage(page) {
this.#activePage = page;
}
getVisiblePagesRange() {
let beginningVisiblePage;
let endingVisiblePage;
// When the visiblepagesendrange % visiblepages is not zero (which means that all the pages cannot be fit in the visible pages range) then the beginning would be equivalent to visble page range - ((visible page range mod visiblepage range) - 1).
if (this.#visiblePagesEndRange % this.#visiblePages !== 0) {
beginningVisiblePage =
this.#visiblePagesEndRange - (this.#visiblePagesEndRange % this.#visiblePages) + 1;
}
// else we are always in a place where, current visible page end range - visible page range + 1 will return us the correct beginning position for the page range.
else {
beginningVisiblePage = this.#visiblePagesEndRange - this.#visiblePages + 1;
}
//Also endingActivePage would be simply equal visiblePagesEndRange.
endingVisiblePage = this.#visiblePagesEndRange;
return {
beginningVisiblePage,
endingVisiblePage
};
}
getActiveRecordsIndices() {
// the beginning page index will be current active page multiplied by no of records.
let beginningRecordIndex = (this.#activePage - 1) * this.#recordsPerPage;
// the ending page index will be minimum of total records and (beginning + records allowed per page);
let endingRecordIndex = Math.min(
beginningRecordIndex + this.#recordsPerPage,
this.#totalRecords
);
return { beginningRecordIndex, endingRecordIndex };
}
}
// All the render and using Paginator class logic comes here
(function () {
function nextPage() {
paginator.gotoNextPage();
render();
}
function prevPage() {
paginator.gotoPrevPage();
render();
}
function lastPage() {
paginator.gotoLastPage();
render();
}
function firstPage() {
paginator.gotoFirstPage();
render();
}
// Delegating event to the parent ul.
function gotoPage(event) {
if (event.target.nodeName === "BUTTON") {
const page = parseInt(event.target.dataset.item);
paginator.gotoPage(page);
render();
}
}
const paginationPages = document.querySelector(".pagination__pages");
paginationPages.addEventListener("click", gotoPage);
/* paginator object
list which is of length 346
recordsPerPage = 6
visiblePages = 6
*/
const paginator = new Paginator(records.length,6, 6);
// Method to render the pagination buttons;
function renderPages() {
const paginationPages = document.querySelector(".pagination__pages");
let html = "";
let {
beginningVisiblePage,
endingVisiblePage
} = paginator.getVisiblePagesRange();
for (let page = beginningVisiblePage; page <= endingVisiblePage; page++) {
const pageClass =
paginator.getActivePage() === page
? "pagination__page-btn--active"
: "pagination__page-btn";
html += `<li class='pagination__page'>
<button data-item=${page} class=${pageClass}>${page}</button>
</li>`;
}
paginationPages.innerHTML = html;
}
// Method to render the list items
function renderList() {
const list = document.querySelector(".list");
const {
beginningRecordIndex,
endingRecordIndex
} = paginator.getActiveRecordsIndices();
let html = "";
for (let index = beginningRecordIndex; index < endingRecordIndex; index++) {
html += `<li class='list__item'>${records[index]}</li>`;
}
list.innerHTML = html;
}
// Main render function
function render() {
renderPages();
renderList();
}
render();
this.firstPage = firstPage;
this.lastPage = lastPage;
this.nextPage = nextPage;
this.prevPage = prevPage;
this.gotoPage = gotoPage;
})();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.