Search code examples
jsonnode.jspaginationexpresstumblr

Numbered page navigation for blog using Node.js and Express


I'm developing a webapp using Node.js and Express. Inside this app, I manage a stream of JSON data to create a blog reader using Tumblr APIs.

I wrote the route as:

app.get('/blog', function(req, res) {

  var Tumblr = require('tumblr').Tumblr
    , keys = require('./keystore');

  // Instancing Tumblr object to connect with a certain blog.
  var blog = new Tumblr('myblog.tumblr.com', keys.tumblrConsumerSecret);

  // Using Tumblr API to retrieve posts from a remote blog.
  // For more info about methods and parameters to use, read the
  // documentation for Tumblr's API v2.
  blog.posts({offset: 0, limit: 5}, function(err, tumblr) {
    if (err) {
       res.send('Error page... I suppose!');
    }
    else {
      res.render('blog',
      {
        blog: tumblr.posts
      });
    }
  }); 
});

And blog.jade:

each post in blog
  h2 #{post.title}
  .justified
    != post.body

Now, I would like to add numbered page navigation function (as server-side) to the reader.

page 1: posts from 1 to 5
page 2: posts from 6 to 10
(etc...)

What can I do that?

Best regards, Vi.


Solution

  • Following chovy's suggestion, I've found a solution.

    In app.js:

    function checkParamPage(req, res, next) {
      if (req.params.page > 0) {
        next();
      }
      else { res.redirect('/error'); }
    }
    
    app.get('/blog/:page', checkParamPage, routes.blog);
    app.get('/error', function(req, res) { res.send('Error!'); })
    

    In routes/index.js:

    exports.blog = function(req, res) {
    
      var _req = req;
      var _res = res;
    
      var Tumblr = require('tumblr').Tumblr
        , keys = require('../keystore')
        , async = require('async');
    
      var page    = req.params.page
        , limit   = 5
        , offset  = page*limit - limit;
    
      // Instancing Tumblr object to connect with a certain blog.
      var blog = new Tumblr('myblog.tumblr.com', keys.tumblrConsumerSecret);
    
      async.parallel([
          function(callback){
            blog.info(function(err, res) {
              if (err) {
                callback('error', null);
              } else {
                callback(null, Math.ceil(res.blog.posts/limit));
              }
            });
          },
          function(callback){
            blog.posts({offset: offset, limit: limit}, function(err, res) {
              if (err) {
                callback('error', null);
              } else {
                if (tumblr.posts.length === 0) {
                  callback('empty', null);
                } else {
                  callback(null, res.posts);
                }
              }
            });
          }
        ], function(err, res) {
          if (err) {
            _res.redirect('/error');
          } else if (page > res[0]) {
            _res.redirect('/error');
          } else {
            _res.render('blog',{
              current: '/blog',
              title: 'MyTitle',
              pages: {
                all: res[0],
                current: page
              },
              posts: res[1]
            });
          }
        }
      );
    };
    

    Then, blog.jade:

    extends layout
    
    block content
    
      // Including sidebar.
      include partials/sidebar
    
      div.span8
        h1 Blog
        hr
    
        each post in posts
          h2 #{post.title}
          div#tumblr-post.justified
            != post.body
          hr
    
        .pagination.pagination-centered
          ul
            if (pages.current > 1)
              li
                a(href='/blog/1') First
            else
              li.disabled
                a(href='/blog/1') First
            - for (var i = 1; i <= pages.all; i++)
              if (i == pages.current)
                li.active
                  a(href='/blog/' + i) #{i}
              else
                li
                  a(href='/blog/' + i) #{i}
            if (pages.current < pages.all)
              li
                a(href='/blog/' + pages.all) Last
            else
              li.disabled
                a(href='#') Last
    
      // Including footer.
      include partials/footer
    

    That's all (and it works fine)!