Client-Side JavaScript Pagination

๐Ÿ‘‹ Ciprian on Tuesday, March 27, 2018 in Featured, JavaScript
Last modified on Wednesday, May 5, 2021

Learn JavaScript by example. Code snippets, how-to's and tutorials. Try now!

? Updated on May 4, 2021 to add a second solution, based on JSON data.
Updated on August 30, 2019 to use the new ES syntax.
Updated on May 25, 2018 to hide Next and Previous links on first and last page.

Server-side pagination is needed when you have to display hundreds of records. You may fetch results from a database using an offset and loading a single page for each HTTP request.

A long time ago, I migrated from List.js to server-side pagination in order to scale a massive result set. For smaller ones – less than 1000 – and when the query is optimized, you can use client-side navigation (i.e. JavaScript pagination).

JavaScript Pagination – Solution #1

If your result set is small, it’s possible to fully load it. In my case, I have an HTML table (a div-based structure is also possible) which needs to be paginated.

Usage

To use this JavaScript pagination script, follow the steps below:

How to implement JavaScript pagination?

  1. Add the JavaScript to your page footer (see full script below).
  2. Add CSS to style the navigation bar (see an example below).
  3. Define an ID on the table you want to scroll.
  4. Place an empty DOM element where you want to display the navigation bar.
  5. Initialise the pager.

That’s all.

If you have a huge table, it may be fully displayed before the JavaScript in the footer will be executed. To avoid this, you can set the table as hidden by default using CSS, and make it visible using JavaScript after the pager.showPage() call.

<table id="pager" class="wp-list-table widefat striped posts">
    <thead>
        <tr>
            <th>Column #1</th>
            <th>Column #2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th>Info #1</th>
            <th>Info #2</th>
        </tr>
        <tr>
            <th>Info #1</th>
            <th>Info #2</th>
        </tr>
        <tr>
            <th>Info #1</th>
            <th>Info #2</th>
        </tr>
    </tbody>
</table>

<div id="pageNavPosition" class="pager-nav"></div>

<script src="PagerJS.js" defer></script>

<script>
let pager = new Pager('pager', 3);

pager.init();
pager.showPageNav('pager', 'pageNavPosition');
pager.showPage(1);
</script>

JavaScript: PagerJS.js

/* eslint-env browser */
/* global document */

function Pager(tableName, itemsPerPage) {
    'use strict';

    this.tableName = tableName;
    this.itemsPerPage = itemsPerPage;
    this.currentPage = 1;
    this.pages = 0;
    this.inited = false;

    this.showRecords = function (from, to) {
        let rows = document.getElementById(tableName).rows;

        // i starts from 1 to skip table header row
        for (let i = 1; i < rows.length; i++) {
            if (i < from || i > to) {
                rows[i].style.display = 'none';
            } else {
                rows[i].style.display = '';
            }
        }
    };

    this.showPage = function (pageNumber) {
        if (!this.inited) {
            // Not initialized
            return;
        }

        let oldPageAnchor = document.getElementById('pg' + this.currentPage);
        oldPageAnchor.className = 'pg-normal';

        this.currentPage = pageNumber;
        let newPageAnchor = document.getElementById('pg' + this.currentPage);
        newPageAnchor.className = 'pg-selected';

        let from = (pageNumber - 1) * itemsPerPage + 1;
        let to = from + itemsPerPage - 1;
        this.showRecords(from, to);

        let pgNext = document.querySelector('.pg-next'),
            pgPrev = document.querySelector('.pg-prev');

        if (this.currentPage == this.pages) {
            pgNext.style.display = 'none';
        } else {
            pgNext.style.display = '';
        }

        if (this.currentPage === 1) {
            pgPrev.style.display = 'none';
        } else {
            pgPrev.style.display = '';
        }
    };

    this.prev = function () {
        if (this.currentPage > 1) {
            this.showPage(this.currentPage - 1);
        }
    };

    this.next = function () {
        if (this.currentPage < this.pages) {
            this.showPage(this.currentPage + 1);
        }
    };

    this.init = function () {
        let rows = document.getElementById(tableName).rows;
        let records = (rows.length - 1);

        this.pages = Math.ceil(records / itemsPerPage);
        this.inited = true;
    };

    this.showPageNav = function (pagerName, positionId) {
        if (!this.inited) {
            // Not initialized
            return;
        }

        let element = document.getElementById(positionId),
            pagerHtml = '<span onclick="' + pagerName + '.prev();" class="pg-normal pg-prev">ยซ</span>';

        for (let page = 1; page <= this.pages; page++) {
            pagerHtml += '<span id="pg' + page + '" class="pg-normal pg-next" onclick="' + pagerName + '.showPage(' + page + ');">' + page + '</span>';
        }

        pagerHtml += '<span onclick="' + pagerName + '.next();" class="pg-normal">ยป</span>';

        element.innerHTML = pagerHtml;
    };
}

Sample CSS

.pager-nav {
    margin: 16px 0;
}
.pager-nav span {
    display: inline-block;
    padding: 4px 8px;
    margin: 1px;
    cursor: pointer;
    font-size: 14px;
    background-color: #FFFFFF;
    border: 1px solid #e1e1e1;
    border-radius: 3px;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
.pager-nav span:hover,
.pager-nav .pg-selected {
    background-color: #f9f9f9;
    border: 1px solid #CCCCCC;
}

JavaScript Pagination – Solution #1 – Demo

See the Pen JavaScript Pagination by Ciprian (@ciprian) on CodePen.

JavaScript Pagination – Solution #2

The second solution is able to get data either manually, client-side generated, or via JSON, server side.

How to implement JavaScript pagination?

  1. Add the JavaScript to your page footer (see the script below or the Codepen demo).
  2. Add the HTML template.
  3. Add your JSON data.
  4. Initialise the pagination.

The HTML is a simple placeholder for the data:

<div id="listing-table"></div>

<p>
    <a href="#" id="btn-prev">Prev</a>
    <a href="#" id="btn-next">Next</a>
</p>

<p>Page <span id="page"></span></p>

The JavaScript is split into 3 parts. The pagination helpers functions:

/**
 * Get the number of items per page based on the length of the JSON object
 * and the number of records per page (set via global variable)
 */
function jsp_num_pages() {
    return Math.ceil(jsp_json_object.length / jsp_records_per_page);
}

/**
 * Change current page to previous page (-1)
 */
function jsp_prev_page() {
    if (jsp_current_page > 1) {
        jsp_current_page--;
        jsp_change_page(jsp_current_page);
    }
}

/**
 * Change current page to next page (+1)
 */
function jsp_next_page() {
    if (jsp_current_page < jsp_num_pages()) {
        jsp_current_page++;
        jsp_change_page(jsp_current_page);
    }
}

/**
 * Change page, display items in
 the table and show/hide the navigation buttons.
 * This function can be further split into several functional elements, thus
 * simplifying the functions and allowing for more complexity (better pagination
 * styling, better table layout and so on).
 */
function jsp_change_page(page) {
    const btn_prev = document.getElementById('btn-prev');
    const btn_next = document.getElementById('btn-next');
    const listing_table = document.getElementById('listing-table');
    let page_span = document.getElementById('page');
 
    if (page < 1) {
        page = 1;
    }
    if (page > jsp_num_pages()) {
        page = jsp_num_pages();
    }

    listing_table.innerHTML = '';

    for (let i = (page - 1) * jsp_records_per_page; i < (page * jsp_records_per_page) && i < jsp_json_object.length; i++) {
        listing_table.innerHTML += `${jsp_json_object[i].json_item}<br>`;
    }
    page_span.innerHTML = `${page}/${jsp_num_pages()}`;

    btn_prev.style.display = (page === 1) ? 'none' : 'inline-block';
    btn_next.style.display = (page === jsp_num_pages()) ? 'none' : 'inline-block';
}

Finally, we need to initialize the pagination and listen to page changes.

window.onload = () => {
    document.getElementById('btn-prev').addEventListener('click', (e) => {
        e.preventDefault();
        jsp_prev_page();
    });

    document.getElementById('btn-next').addEventListener('click', (e) => {
        e.preventDefault();
        jsp_next_page();
    });

    jsp_change_page(1);
};

This second solution has no styling (for demo purposes) and is more flexible when adding new pagination items.

JavaScript Pagination – Solution #2 – Demo

See the Pen JSP #3 by Ciprian (@ciprian) on CodePen.

Find more JavaScript tutorials, code snippets and samples here or more jQuery tutorials, code snippets and samples here.

Buy me a coffee to support my work!

๐Ÿ‘‹ Added by Ciprian on Tuesday, March 27, 2018 in Featured, JavaScript. Last modified on Wednesday, May 5, 2021.

8 comments on “Client-Side JavaScript Pagination

    1. This is not a final script, though, it’s something to get you started. It can be improved upon and more features can be added, but it’s outside the scope of this article.

    1. Which solution are you talking about? I also assume you’re talking about using multiple tables on the same page, not website.

      However, the general rule is either to use different table IDs/classes or use a loop to get all table elements.

      You’d definitely need to make some changes to both solutions to accommodate multiple tables.

  1. JavaScript Pagination โ€“ Solution #2 โ€“ Demo

    its get only json values in the table
    { json_item: “Item 1”},
    { json_item: “Item 2”},
    { json_item: “Item 3”},
    { json_item: “Item 4”},
    { json_item: “Item 5”},
    how to use our html table

Leave a Reply

You have to agree to the comment policy.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Privacy Policy