How to Accurately Calculate and Display Pagination Indexes in JavaScript
This guide explains common pagination index problems in web apps and provides a step‑by‑step JavaScript solution—including a reusable function, a full HTML component, handling of empty and dynamic data sets, best‑practice tips, and complete code examples—for seamless user navigation.
Problem Analysis
In many web applications a pagination UI must display a range such as "Showing 1‑10 of 100". Common pitfalls include:
When the last page contains fewer items the calculated range can be wrong.
Deleting records may leave gaps in the displayed index sequence.
Search or filter results often cause mis‑calculated indexes because the total record count changes.
Solution
Basic Index Calculation
function calculatePageIndexes(currentPage, pageSize, totalRecords) {
const startIndex = (currentPage - 1) * pageSize + 1;
const endIndex = Math.min(currentPage * pageSize, totalRecords);
return { start: startIndex, end: endIndex, total: totalRecords };
}
// Example usage
const pageInfo = calculatePageIndexes(2, 10, 85);
console.log(`Showing ${pageInfo.start}-${pageInfo.end} records, total ${pageInfo.total}`);Full Pagination Component (HTML & JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pagination Index Example</title>
</head>
<body>
<div id="recordsInfo">Loading...</div>
<button id="prevBtn">Prev</button>
<div id="pageNumbers"></div>
<button id="nextBtn">Next</button>
<script>
const mockData = Array.from({ length: 97 }, (_, i) => `Record ${i + 1}`);
const paginationState = { currentPage: 1, pageSize: 10, totalRecords: mockData.length };
function calculatePageIndexes(currentPage, pageSize, totalRecords) {
const startIndex = (currentPage - 1) * pageSize + 1;
const endIndex = Math.min(currentPage * pageSize, totalRecords);
return { start: startIndex, end: endIndex, total: totalRecords };
}
function calculateTotalPages(pageSize, totalRecords) {
return Math.ceil(totalRecords / pageSize);
}
function updateDisplay() {
const idx = calculatePageIndexes(paginationState.currentPage, paginationState.pageSize, paginationState.totalRecords);
document.getElementById('recordsInfo').textContent = `Showing ${idx.start}-${idx.end} records, total ${idx.total}`;
updatePaginationButtons();
}
function updatePaginationButtons() {
const totalPages = calculateTotalPages(paginationState.pageSize, paginationState.totalRecords);
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const pageNumbers = document.getElementById('pageNumbers');
prevBtn.disabled = paginationState.currentPage === 1;
nextBtn.disabled = paginationState.currentPage === totalPages;
pageNumbers.innerHTML = '';
let startPage = Math.max(1, paginationState.currentPage - 3);
let endPage = Math.min(totalPages, startPage + 6);
if (endPage - startPage < 6 && startPage > 1) {
startPage = Math.max(1, endPage - 6);
}
for (let i = startPage; i <= endPage; i++) {
const btn = document.createElement('button');
btn.className = i === paginationState.currentPage ? 'page-btn active' : 'page-btn';
btn.textContent = i;
btn.addEventListener('click', () => {
paginationState.currentPage = i;
updateDisplay();
});
pageNumbers.appendChild(btn);
}
}
document.getElementById('prevBtn').addEventListener('click', () => {
if (paginationState.currentPage > 1) {
paginationState.currentPage--;
updateDisplay();
}
});
document.getElementById('nextBtn').addEventListener('click', () => {
const totalPages = calculateTotalPages(paginationState.pageSize, paginationState.totalRecords);
if (paginationState.currentPage < totalPages) {
paginationState.currentPage++;
updateDisplay();
}
});
updateDisplay();
</script>
</body>
</html>Handling Special Cases
Empty Dataset
function calculatePageIndexes(currentPage, pageSize, totalRecords) {
if (totalRecords === 0) {
return { start: 0, end: 0, total: 0 };
}
const startIndex = (currentPage - 1) * pageSize + 1;
const endIndex = Math.min(currentPage * pageSize, totalRecords);
return { start: startIndex, end: endIndex, total: totalRecords };
}Dynamic Datasets (Search / Filter)
function handleSearchResults(results, pageSize) {
const totalRecords = results.length;
paginationState.currentPage = 1;
paginationState.totalRecords = totalRecords;
updateDisplay();
renderCurrentPageData(results);
}
function renderCurrentPageData(results) {
const startIndex = (paginationState.currentPage - 1) * paginationState.pageSize;
const endIndex = Math.min(paginationState.currentPage * paginationState.pageSize, results.length);
const pageData = results.slice(startIndex, endIndex);
// render pageData ...
}Best Practices
Validate that currentPage and pageSize are positive integers before performing calculations.
Explicitly handle edge cases such as an empty dataset or a dataset that fits on a single page.
Provide clear UI feedback when there is no data or only one page (e.g., hide pagination controls or show a placeholder message).
For very large collections consider virtual scrolling or infinite scrolling to avoid rendering a large number of page buttons.
Conclusion
Accurate pagination index calculation is essential for a smooth user experience. The functions and component presented work for standard pagination, datasets smaller than a full page, dynamic changes (search, filter, deletion), and boundary conditions, enabling a robust and intuitive data navigation system.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
php Courses
php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
