Pagination functionality using js rudders
I am developing pagination functionality using js descriptors and retrieving data from JSON.
-
The first 5 results will be displayed on page load.
-
clicking the next pagination will display another set of 5 results, and so on.
-
If I have a total of 100 results displaying every 5 results on the page. The page numbers will be 1 out of 20.
- if there are more than 5 pages in the folder, I want to display "1,2,3 ... last Page Number (20)" the same vice versa
- when loading Previous button Should be hidden when clicking on the next page, it should be enabled.
Feel free to contact us, please read this and give some advice / suggestions on this matter.
Should be lower
Appreciate your kind help!
thank
-
example code:
$(function () { var opts = { pageMax: 5, postsDiv: $('#posts'), dataUrl: "searchResult.json" } function range(i) { return i ? range(i - 1).concat(i) : [] } function loadPosts(posts) { opts.postsDiv.empty(); posts.each(function () { var source = $("#post-template").html(); var template = Handlebars.compile(source); var context = { title: this.title, desc: this.body, }; var html = template(context); opts.postsDiv.append(html); }); } function paginate(pageCount) { var source = $("#pagination-template").html(); var template = Handlebars.compile(source); var context = { pages: range(pageCount) }; var html = template(context); opts.postsDiv.after(html); function changePage(pageNumber) { pageItems.removeClass('active'); pageItems.filter('[data-page="' + pageNumber + '"]').addClass('active'); loadPosts(data.slice(pageNumber * opts.pageMax - opts.pageMax, pageNumber * opts.pageMax)); } var pageItems = $('.pagination>li.pagination-page'); pageItems.on('click', function () { changePage(this.getAttribute('data-page')); }).filter('[data-page="1"]').addClass('active'); $('.pagination>li.pagination-prev').on('click', function () { gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) - 1; if (gotoPageNumber <= 0) { gotoPageNumber = pageCount; } changePage(gotoPageNumber); }); $('.pagination>li.pagination-next').on('click', function () { gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) + 1; if (gotoPageNumber > pageCount) { gotoPageNumber = 1; } changePage(gotoPageNumber); }); } $.ajax({ dataType: 'json', url: opts.dataUrl, success: function (response_json) { data = $(response_json.records.page); dataCount = data.length; pageCount = Math.ceil(dataCount / opts.pageMax); if (dataCount > opts.pageMax) { paginate(pageCount); posts = data.slice(0, opts.pageMax); } else { posts = data; } loadPosts(posts); } }); });
source to share
I had to solve a similar problem a few months ago. I found this Gist from kottenator.
Your range function changes in this way, which c
is the current page, and m
is yours pageCount
. The function call has been slightly modified, and a recursive call to your function has paginate(...)
also been added to recompile the tag after navigation (also added a branch to your DOM add function calls to change the pagination tag, I used ternary operator. It might be more elegant for that ).
See this CodePen
function range(c,m) {
var current = c || 1,
last = m,
delta = 2,
left = current - delta,
right = parseInt(current) + delta + 1,
range = [],
rangeWithEllipsis = [],
l,
t;
range.push(1);
for (var i = c - delta ; i <= c + delta ; i++) {
if (i >= left && i < right && i < m && i > 1) {
range.push(i);
}
}
range.push(m);
for (var i of range) {
if (l) {
if (i - l === 2) {
t = l+1;
rangeWithEllipsis.push(t);
} else if (i - l !== 1) {
rangeWithEllipsis.push("...");
}
}
rangeWithEllipsis.push(i);
l = i;
}
return rangeWithEllipsis;
}
It doesn't exactly solve your problem in one go, but it paginates correctly.
If I have some time, I will try to make it look the way you want it to (this is really just setting the personalization of the operands delta
, left
and right
in the algorithm, and also changing the pagination and paging of the prev event handler).
Edit . I changed the algorithm to find the border left
and right
. Yours is index.html
also slightly modified.
The idea is to compute the left and right margins in multiples of 5. Then you create a range of indices to display and add elipsis if the difference is too big. This should effectively solve your original problem.
JavaScript
getFirstDigits = (t) => {
return parseInt(t.toString().slice(0,-1))
}
getLastDigit = (t) => {
return parseInt(t.toString().slice(-1))
}
isMultipleOf5 = (t) => {
return [0,5].reduce((res,curr)=>{
return res = res || curr === getLastDigit(t);
},false);
}
isBetween0and5 = (t) => {
const _t = getLastDigit(t);
return _t < 5;
}
isBetween5and9 = (t) => {
const _t = getLastDigit(t);
return _t => 5 && _t <= 9;
}
appendDigit = (t,d) => {
return parseInt(getFirstDigits(t).toString() + d.toString())
}
getSecondRightMostDigit = (t) => {
return parseInt(t.toString().slice(-2,-1))
}
incrementSecondDigit = (t) => {
return t+10;
}
getLeft = (t) => {
if(t>=10){
if(isBetween0and5(t)) return appendDigit(t,0);
else return appendDigit(t,5);
} else {
if (t<5) return 0;
else return 5;
}
}
getRight = (t) => {
if(t<5) return 5;
else if (t<10) return 10;
else if(isBetween0and5(t)) return appendDigit(t,5)
else return appendDigit(incrementSecondDigit(t),0);
}
function range(c,m) {
var current = c || 1,
last = m,
delta = 2,
left = getLeft(c),
right = getRight(c),
range = [],
rangeWithEllipsis = [],
l,
t;
var rightBoundary = right < 5 ? 5 : right;
for (var i = left ; i < rightBoundary ; ++i) {
if( i < m && i > 0) range.push(i);
}
range.push(m);
for (var i of range) {
if (l) {
if (i - l === 2) {
t = l+1;
rangeWithEllipsis.push(t);
} else if (i - l !== 1){
rangeWithEllipsis.push("...");
}
}
rangeWithEllipsis.push(i);
l = i;
}
return rangeWithEllipsis;
}
HTML / Steering Wheels
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Handlebars Pagination</title>
<link href="main.css" rel="stylesheet" />
<script src="jquery.min.js"></script>
<script src="handlebars.min.js"></script>
<script src="functions.js"></script>
</head>
<body class="container">
<div id="posts"></div>
<script id="pagination-template" type="text/x-handlebars-template">
<ul class="pagination">
<li class="pagination-prev"><a href="#">«</a></li>
{{#each pages}}
<li class="pagination-page" data-page="{{this}}"><a href="#">{{this}}</a></li>
{{/each}}
<li class="pagination-next"><a href="#">»</a></li>
</ul>
</script>
<script id="post-template" type="text/x-handlebars-template">
<div class="score-structural score-column2-wideright search-listings post">
<div class="score-right">
<h4>{{record_count}}</h4>
<h5 style="z-index: 1;">
<a href="#"> {{ title }} </a>
</h5>
<p style="z-index: 1;"> {{ desc }} </p>
</div>
</div>
<hr>
</script>
</body>
</html>
<script>
$(function () {
var opts = {
pageMax: 2,
postsDiv: $('#posts'),
dataUrl: "searchResult.json"
}
function loadPosts(posts) {
opts.postsDiv.empty();
posts.each(function () {
var source = $("#post-template").html();
var template = Handlebars.compile(source);
var context = {
title: this.title,
desc: this.body,
};
var html = template(context);
opts.postsDiv.append(html);
});
hidePrev();
}
function hidePrev() { $('.pagination .pagination-prev').hide(); }
function showPrev() { $('.pagination .pagination-prev').show(); }
function hideNext() { $('.pagination .pagination-next').hide(); }
function showNext() { $('.pagination .pagination-next').show(); }
function paginate(page,pageCount) {
var source = $("#pagination-template").html();
var template = Handlebars.compile(source);
var context = { pages: range(page,pageCount) };
console.log(range(page,pageCount));
var html = template(context);
var paginationTag = opts.postsDiv.parent().find(".pagination");
paginationTag.length > 0 ? paginationTag.replaceWith(html) : opts.postsDiv.before(html);
function changePage(page) {
pageItems.removeClass('active');
pageItems.filter('[data-page="' + page + '"]').addClass('active');
loadPosts(data.slice(page * opts.pageMax - opts.pageMax, page * opts.pageMax));
paginate(page,pageCount);
if (gotoPageNumber <= 1) {
hidePrev();
}
}
var pageItems = $('.pagination>li.pagination-page');
var pageItemsLastPage = $('.pagination li').length - 2;
pageItems.removeClass('active');
pageItems.filter('[data-page="' + page + '"]').addClass('active');
pageItems.on('click', function () {
getDataPageNo = this.getAttribute('data-page')
console.log(getDataPageNo)
changePage(getDataPageNo);
if (getDataPageNo == 1) {
hidePrev()
}
else if (getDataPageNo == pageItemsLastPage) {
hideNext();
}
else {
showPrev();
showNext();
}
});
$('.pagination>li.pagination-prev').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) - 1;
changePage(gotoPageNumber);
});
$('.pagination>li.pagination-next').on('click', function () {
gotoPageNumber = parseInt($('.pagination>li.active').attr('data-page')) + 1;
if (gotoPageNumber > pageCount) {
gotoPageNumber = 1;
showPrev();
}
changePage(gotoPageNumber);
});
}
$.ajax({
dataType: 'json',
url: opts.dataUrl,
success: function (response_json) {
data = $(response_json.records.page);
dataCount = data.length;
pageCount = Math.ceil(dataCount / opts.pageMax);
if (dataCount > opts.pageMax) {
paginate(1,pageCount);
posts = data.slice(0, opts.pageMax);
} else {
posts = data;
}
loadPosts(posts);
}
});
});
</script>
source to share