Pagination
What is pagination?
Pagination (paging) is used to divide the products into pages. Instead of having a long page with all of the products we can limit each page to include a set number of products.
Prepare the pagination <div>
wrapper in both the index.html
and dashboard.html
pages:
<!-- clear contents from inside the
pagination div and add class/id attributes -->
<div id="pagination" class="pagination"></div>
The contents of these pagination areas will be generated using JavaScript. As both pages use the same pagination
id the pagination will work on both pages. Create two new variables near the top of the script:
// script.js
let currentPage = 1;
const ITEMS_PER_PAGE = 5;
currentPage
: this is used to store the current page we are viewing.ITEMS_PER_PAGE
: containes the number of products to show on each page. Although not required, aconst
is often named using upper case. Since we only request 20 products, this number will give us 4 pages to test with.
Limiting products per page
The renderProducts()
function currently displays all available products onto the page, modify this function to slice
the products we need for the current page:
function renderProducts() {
const productList = document.getElementById("product-list");
const productTable = document.getElementById("product-table");
// add the following 3 lines
const start = (currentPage - 1) * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE;
const currentProducts = products.slice(start, end);
if (window.location.pathname.includes("dashboard.html")) {
// replace products with currentProducts
renderTableRows(productTable, currentProducts);
} else {
// replace products with currentProducts
renderProductCards(productList, currentProducts);
}
}
products.slice(start, end)
: theslice
array method is used to create a copy of the original (products
) array. The new array will be a selection of the values cut from a start and end position of the original array. These positions can be entered as a number or, we are using variables to calculate.products
is then replaced withcurrentProducts
to render the filtered version.
The start
and end
variables are used to slice values from the original products array. Arrays begin at zero, if is we set 5 products per page, page 1 will be values 0-4. Page 2 will be values 5-9 and so on. For the start
we need to -1
to account for the array beginning at zero.
Pagination buttons
To create the buttons to select the page, we first need to know how many pages we have. Create a function to handle this at the bottom of the script.js
:
function createPaginationButtons() {
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const pagination = document.getElementById("pagination");
}
products.length
: We can access the number of values in an array with thelength
property. This is divided by the products per page we set to give us the number of pages.Math.ceil()
: This number of pages caclulation is rounded up to the nearest whole number.
To create a button for each page, add a for
loop:
function createPaginationButtons() {
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const pagination = document.getElementById("pagination");
for (let i = 1; i <= totalPages; i++) {
}
}
for() {}
: Thefor
loop will run the code between the curly braces a number of times. The number of times is determined by 3 optional expressions.let i = 1;
: The first expression runs before the code block, this will set a variable to be the number1
.i <= totalPages;
: The loop will keep running as long as this condition is true. As long asi
is less than/equal to thetotalPages
variable it will continue.i++
: The final expression runs after each loop has completed. This will increment (increase) thei
variable by a value of 1. Meaningi
will increase in value on each repetition of the loop, until reaching thetotalPages
value.
The loop runs from 1 to totalPages
, creating a button for each page. Complete the contents of the loop to create the HTML button
elements:
function createPaginationButtons() {
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const pagination = document.getElementById("pagination");
for (let i = 1; i <= totalPages; i++) {
const button = document.createElement("button");
button.textContent = i;
// Ensure only the currentPage button has the "active" class
if (i === currentPage) {
button.classList.add("active");
}
button.addEventListener("click", function() {
currentPage = i;
renderProducts();
// Refresh pagination buttons to update active class
createPaginationButtons();
});
pagination.appendChild(button);
}
}
The event listener
The above code attaches an event listener to the button
using addEventListener
. Event examples include when a HTML page has loaded, a mouse moves over an element, or a keboard button is pressed. Our use case is a button is clicked. This will run a function:
function() {
currentPage = i;
renderProducts();
createPaginationButtons();
}
When a button is clicked, currentPage
is updated to i
(the clicked page number). We call renderProducts()
to display the products for the current page selection. Finally, createPaginationButtons()
will refresh the pagination buttons to update the active class.
To run the createPaginationButtons
function, call it after fetching the products:
async function fetchProducts() {
const response = await fetch(API_URL);
const data = await response.json();
products = data.data;
// call function to create buttons
createPaginationButtons();
renderProducts();
}
Try this out and you will notice after clicking a page button, the products are added to the previous ones.
Clearing existing products
To resolve this we need to clear the existing products before generating new ones. Update the renderProducts()
function to clear the innerHTML
for both pages:
if (window.location.pathname.includes("dashboard.html")) {
// clear content of productTable
productTable.innerHTML = "";
renderTableRows(productTable, currentProducts);
} else {
// clear content of productList
productList.innerHTML = "";
renderProductCards(productList, currentProducts);
}
Also clear the previously created buttons at the top of the createPaginationButtons
function:
function createPaginationButtons() {
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const pagination = document.getElementById("pagination");
// clear buttons
pagination.innerHTML = "";
Test this out by clicking on the page buttons to switch between products!
Final script.js
code
let products = [];
const API_URL = "https://fakerapi.it/api/v2/products?_quantity=20";
let currentPage = 1;
const ITEMS_PER_PAGE = 5;
async function fetchProducts() {
const response = await fetch(API_URL);
const data = await response.json();
products = data.data;
createPaginationButtons();
renderProducts();
}
fetchProducts();
function renderProducts() {
const productList = document.getElementById("product-list");
const productTable = document.getElementById("product-table");
const start = (currentPage - 1) * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE;
const currentProducts = products.slice(start, end);
if (window.location.pathname.includes("dashboard.html")) {
productTable.innerHTML = "";
renderTableRows(productTable, currentProducts);
} else {
productList.innerHTML = "";
renderProductCards(productList, currentProducts);
}
}
function renderProductCards(container, products) {
products.forEach(function (product) {
const card = document.createElement("article");
card.setAttribute("class", "product-card");
card.innerHTML = `<section class="product-image">
<img
src="images/t-shirt-blue.png"
alt="blue t-shirt with short sleeves"
class="product-image"
/>
</section>
<section class="product-details">
<h3>${product.name}</h3>
<p>${product.description}</p>
<p class="price">$${product.price}</p>
</section>`;
container.appendChild(card);
});
}
function renderTableRows(container, products) {
products.forEach(function(product) {
const row = document.createElement("tr");
row.innerHTML = `
<td>${product.name}</td>
<td>$${product.price}</td>
<td>
<button class="edit-btn">Edit</button>
<button class="delete-btn">Delete</button>
</td>
`;
container.appendChild(row);
});
}
function createPaginationButtons() {
const totalPages = Math.ceil(products.length / ITEMS_PER_PAGE);
const pagination = document.getElementById("pagination");
pagination.innerHTML = "";
for (let i = 1; i <= totalPages; i++) {
const button = document.createElement("button");
button.textContent = i;
if (i === currentPage) {
button.classList.add("active");
}
button.addEventListener("click", function () {
currentPage = i;
renderProducts();
createPaginationButtons();
});
pagination.appendChild(button);
}
}