Saturday, June 9, 2018

How to Create Infinite Scroll Pagination in single page application using nodejs

In the web application if you have to display lots of data then you must have to get data as per required using pagination.

if you have more than 10000 records/data and get all at page load then your app will stuck/takes too much time to load.

to overcome this problem here, we will discuss how to get Endless Scrolling data means Ajax scroll down pagination.

how a day, view more record on scroll pagination is becoming more popular and famous in the web application.

here, we have used simple jquery in javascript for pagination. you can also implement this demo in angularJs 1, angular 2, angular 4, angular 5, angular 6, .... and in any template engine or any front-end framework.

in back-end now we have use nodejs, expressjs with MongoDB database and mongoose as a modeling tool, but you can also use this logic in PHP and MySql also.

Demo: article_list.html
<!DOCTYPE html>
<html>

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
</body>

<script type="text/javascript">

var isProcessPending = false; // for stop multiple request simultaneously

var recordsPerPage = 20; // you can set as you want to get data per ajax request
var recordsOffset = 0; // get data from given no
var recordsTotal = 0; // store total number of record

var article_list = [];

//get first time article as page load
loadArticle({ action: "initialization" });

function loadArticle(params) {
    if (!!params && params.action === "VIEW_MORE") {
        recordsOffset = recordsOffset + recordsPerPage;
    }

    $.ajax({
        url: "/api/article/get",
        type: "get", //send it through get method
        data: {
            recordsPerPage: recordsPerPage,
            recordsOffset: recordsOffset
        },
        success: function(response) {
            //Do Something
            isProcessPending = false; // for make process done so new data can be get on scroll

            if (!!params && params.action === "VIEW_MORE") {
                article_list = article_list.concat(response.data.article_list);
            } else {
                if (recordsOffset === 0) {
                    article_list = response.data.article_list;
                    recordsTotal = response.data.recordsTotal;
                }
            }

            console.log("article list");
            console.log(article_list); // form this you can append or manage html as you want

        },
        error: function(xhr) {
            //Do Something to handle error
            isProcessPending = false; // for make process done so new data can be get on scroll
        }
    });

}

//on scroll new get data
$(window).scroll(function() {
    var scrollPercent = Math.round(($(window).scrollTop()) / ($(document).height() - $(window).height()) * 100);
    // get new data only if scroll bar is greater 70% of screen
    if (scrollPercent > 70) {
        //this condition only satisfy ony one pending ajax completed and records offset is less than  total record
        if (isProcessPending === false && recordsOffset < recordsTotal) {
            isProcessPending = true;
            loadArticle({ action: "VIEW_MORE" });
        }

    }
});
</script>
</body>

</html>

article.js (nodejs side api)
var express = require('express');
var router = express.Router();
var async = require('async');
var Article = require('../models/article');

/**
 * Get article list
 */
router
    .route("/api/article/get")
    .get(
        function (req, res) {
            var recordsPerPage = req.query.recordsPerPage !== undefined && req.query.recordsPerPage !== '' ? req.query.recordsPerPage : 20;
            var recordsOffset = req.query.recordsOffset !== undefined && req.query.recordsOffset !== '' ? req.query.recordsOffset : 0;

            //final data object
            var data = {};

            var condition = {};
            condition.is_active = 1;
         
            var options = {};
            options.skip = parseInt(recordsOffset);
            options.limit = parseInt(recordsPerPage);

            async.parallel([
                function (cb) {
                    //get articles as per condition
                    Article.find(condition,
                            'article_name article_image')
                        .skip(options.skip)
                        .limit(options.limit)
                        .exec(function (err, articleList) {
                            if (err) {
                                var err = {
                                    status: 0,
                                    message: "Oops! something went wrong, please try again later."
                                };
                                cb(err);
                            } else {
                                data.article_list = article_list;
                                cb(null);
                            }
                        });
                },
                function (cb) {
                    //get users count as par condition
                    if(recordsOffset === 0){
                        Article.find(condition, function (err, articleCounter) {
                            if (err) {
                                var err = {
                                    status: 0,
                                    message: "Oops! something went wrong, please try again later."
                                };
                                cb(err);
                            } else {
                                data.recordsTotal = articleCounter;
                                cb(null);
                            }
                        });
                    }else{
                        cb(null);
                    }
                },
            ], function (err) {
                //get final result and send the response to API.
                if (err) {
                    res.json(err);
                } else {
                    res.json({
                        status: 1,
                        code: 200,
                        type: "success",
                        data: data
                    });
                }
            });
        });

module.exports = router;

In this demo, we can manage pagination easily by using recordsPerPage, recordsOffset, recordsTotal variables.

recordsPerPage variable is only responsible for determining how many records should be getting at a time on ajax request call

recordsOffset variable is used for skip data / from which index get the record.

recordsTotal variable is used to stop pagination as recordsOffset is equal to or greater than this.

now a day, load more record on reach at the end of data/page is becoming most popular and famous for lazyload/load more data on scroll without click on view more button or any link.

For create infinite scroll pagination directive in angular 2, angular 4, angular 5, angular 6, angular 7, angular 8, etc check following link

https://laxmanchavda.blogspot.com/2019/06/create-infinite-scroll-pagination-directive-in-angular.html

2 comments: