Node.js – Ajax Pagination without the Pages

N

With my recent endeavours into Node, I thought that taking a fun article like this one – CakePHP 2-0 Ajax Pagination WITHOUT The Pages – would be a really fun experiment to see how difficult it would be to accomplish in Node.

At the end of the day, the logic is still the exact same, retrieve the items, determine the max length, calculate the number of pages, and then perform AJAX as well scroll down to fill in more content as-needed.

Leveraging the Express API and Jade templates, this is quite painless to implement into Node with jQuery template.

Before starting, it’s important that you have a basic knowledge of Node, the Express API, and as well Jade templating.  If you don’t, take a quick gander at these previous introductory articles I’ve written:

Now that you have the basics down, let’s get started.  Firstly, let me layout the folder structure and files required to complete this example:

[code]
/

public/
js/

jquery.min.js

paging.js

views/

partials/

items.jade

items.json

index.jade

layout.jade

app.js

[/code]

Most of the files should be pretty familiar from our previous examples.  The Jquery.min.js file can be included externally if you like or you can have a local copy included.  I’ll provide examples for the remaining files.

The example below will create an array, if you’re looking for information about JavaScript arrays I’ve compile an entire page dedicated with over 10 different examples that will considerably improve your skills with Javascript arrays.

Let’s start with the app.js file:

[code]
var express = require(‘express’), jade = require(‘jade’);
var app = express();

var fs = require(‘fs’);
var items;
var itemsPerPage = 2;
var maxPages = 0;
fs.readFile(‘views/partials/items.json’, ‘utf8’, function(error, data) {
items = JSON.parse(data);
maxPages = items.length / itemsPerPage;
});

var pub = __dirname + ‘/public’;

app.use(app.router);
app.use(express.static(pub));
app.use(express.errorHandler());
app.set(‘views’, __dirname + ‘/views’);
app.set(‘view engine’, ‘jade’);

app.get(‘/’, function(req, res) {
res.render(‘index.jade’, {
pageTitle: ‘Test’,
items: items.slice(0, 2),
maxPages: maxPages,
layout: true
});
});

app.get(‘/page/:page’, function(req, res) {
var page = req.params.page;
var start = (page – 1) * 2;
var end = page * 2;

res.render(‘partials/items.jade’, {
pageTitle: ‘Test’,
items: items.slice(start, end),
layout: false
});
});

app.listen(8000);
[/code]

Hopefully you are not immediately overwhelmed by the code, once we break it down a bit more, it should make a lot of sense.

Lines 1 and 2 are the same as before, simply setting up Express and Jade.  Line 4 through 11 are doing something a little new.  I’m including the ability to use the file stream (fs) and reading the aforementioned items.json file.  Once the file is read, the JSON values are stored in the local variable items.  Once loaded, I’m also calculating the maximum pages that are to be displayed by dividing by the number of items I want per page, in this case 2.

Lines 13 through 19 are simply configuring Express and Jade to work together as well as configuring the public folder to serve any Javascript or CSS files that we might have. Something that might be good as a next step is how-to Access query string parameters with Express and Node.js.

And finally, lines 21 through 40 are two routes that have been setup to render the view and display the items on screen.  In the first route (/), I’m simply passing the first two items of the items array to the view.  Whereas, in the second route, based on the page request parameter, I’m calculating the start and end position of the items to display.

Next, let’s create this mysterious views/partials/items.json file:

[code]
[

{“title”: “My first title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My second title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My third title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My fourth title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My fifth title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My sixth title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My seventh title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My eighth title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My ninth title”, “body”: “Lorem ipsum dolor sit …”},

{“title”: “My tenth title”, “body”: “Lorem ipsum dolor sit …”}

]
[/code]

This file contains some placeholder dummy data in a JSON array containing a Javascript event handler with a title and body.  This will be used when I output the content.  In your own code, this would probably be something retrieved from your database…

Next, let’s create the three view files mentioned above starting with the simplest, views/partials/items.jade:

[code]
#items
for item in items
.item
h2= item.title
p= item.body
[/code]

This file outputs the title in an h2, the body in a p tag all wrapped in a div with the class of item and all wrapped in an outer div with the id of items.  The for loop is looping through the items variable that was passed to the layout from the app.js file.

Next is the basic views/index.jade file:

[code]
extends layout

block content
h2 Welcome
include partials/items
[/code]

This file is pretty basic and just includes the previously created partial view.  The last view to create is the views/layout.jade file:

[code]
!!! 5
html(lang+”en”)
head
title= pageTitle
block scripts
script
var maxPages= #{maxPages};
script(src=’/js/jquery.min.js’)
script(src=’/js/paging.js’)

style
#items { width: 300px; }
body
h1 Test
block content
[/code]

The only noticeable thing happening above is on line 8 where I am creating a global variable called maxPages and setting it to the previously created maxPages variable that was calculated after loading the items.

You will also notice that I’m including a Javascript file called js/paging.js, this file should be created in your public directory as it contains the magic to perform the AJAX to request the next items:

[code]
var lastX = 0;
var currentX = 0;
var page = 1;

$(window).scroll(function () {
if (page < maxPages) {
currentX = $(window).scrollTop();
if (currentX – lastX > 200 * page) {
lastX = currentX;
page++;
$.get(‘/page/’ + page, function(data) {
$(‘#items’).append(data);
});
}
}
});
[/code]

As a person scrolls down the page, I’m doing a calculation to determine if a new page should be loaded.  By keeping track of the last scroll position, the code is smart enough to not load additional content when the user scrolls up, and then back down again.

You can view the full source on GitHub here: https://github.com/endyourif/NodeDynamicPaging.

Other useful articles

About the author

By Jamie

My Books