getButterfly
Resume

Client-Side HTML Pagination with JavaScript

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

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

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

Usage

To use this pagination, follow the steps below:

  1. Include the JavaScript using <script src="PagerJS.js" defer></script> in your page footer (see full script below);
  2. Include a bit of CSS to style the navigation bar (see an example below);
  3. Define an ID on the table you want to scroll. (i.e. <table id="pager" class="wp-list-table widefat striped posts">);
  4. Place an empty <div> in the place you want to display the navigation bar. (i.e. <div id="pageNavPosition" class="pager-nav"></div>);
  5. Initialization the pager:
    <script>
    var pager = new Pager('pager', 3); 
    pager.init(); 
    pager.showPageNav('pager', 'pageNavPosition'); 
    pager.showPage(1);
    </script>

That’s all. If you want to download a demo (html+javascript files), you can click here: JavaScript Table Paginator Demo.

If you have a huge table, maybe it will be displayed fully before the javascript at the bottom will be executed. To avoid this, you can set the table as hidden by default using css style, and make it visibile using JavaScript after the pager.showPage() call.

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) {
        var rows = document.getElementById(tableName).rows;

        // i starts from 1 to skip table header row
        for (var 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;
        }

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

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

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

    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 () {
        var rows = document.getElementById(tableName).rows;
        var records = (rows.length - 1);

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

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

        var element = document.getElementById(positionId),
            pagerHtml = '<span onclick="' + pagerName + '.prev();" class="pg-normal">&#171;</span>';

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

        pagerHtml += '<span onclick="' + pagerName + '.next();" class="pg-normal">&#187;</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;
    box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.pager-nav span:hover,
.pager-nav .pg-selected {
    background-color: #f9f9f9;
    border: 1px solid #CCCCCC;
}

===

@TODO:

1. Hide Next link in last page (version 1):

this.showPage = function(pageNumber) {
    ...
    this.showRecords(from, to);

    var pgNext = document.getElementById('pgNext');
    var pgPrev = document.getElementById('pgPrev');

    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.showPageNav = function(pagerName, positionId) {
    ...
    var pagerHtml = '<span id="pgPrev" onclick="' + pagerName + '.prev();" class="pg-normal">&#171;</span>';
    ...
    pagerHtml += '<span id="pgNext" onclick="' + pagerName + '.next();" class="pg-normal">&#187;</span>';

    element.innerHTML = pagerHtml;
}

2. Hide Next link in last page (version 2):

var pgNext = document.getElementById('pgNext');
var pgPrev = document.getElementById('pgPrev');

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

if (pageNumber === 1) {
    pgPrev.style.display = 'none';
} else {
    pgPrev.style.display = 'block';
}

3. Demo


Leave a Reply


My Battle Tested Recommendations

Jetpack
Dreamhost
WordPress.com
CodeCanyon
SEMrush

Disclaimer: These recommendations contain affiliate links.