0

I have a few documentation pages I want to serve. Instead of writing something like the following, I want to essentially server them all without writing this code for every page:

jade.renderFile("/documentation/gettingStarted", {}, function(err, str) {
    if(err) throw err;
    response.send(str);
});

I also would like a simple "Next Page" at the bottom of these pages, with order defined in the following array:

var pages = ["installation", "gettingStarted"];

The part I'm stuck on is that iterating through each page in my array with app.get:

for(var i = 0; i < pages.length; i++) {
    var pagePath = "documentation/" + pages[i];

    app.get("/" + pagePath, function(request, response) {
        jade.renderFile(pagePath + ".jade", {}, function(err, str) {
            if(err) throw err;
            response.send(str);
        });
    });
}

With the block above I would hope that it would server pages on the following requests:

  • /documentation/installation
  • /documentation/gettingStarted

It works for one page, but due to the fact jade.renderFile(...) is called on GET, it will simply use the variables left over from the initialisation, meaning both pages will only return the last page (gettingStarted) because pagePath will be kept the same for both requests.

Is there anyway to serve a bunch of files dynamically? Is it required to make call app.get for every individual page?

AquaGeneral
  • 155
  • 1
  • 19
  • 2
    To learn how to make your loop work, see http://stackoverflow.com/a/3572616/711902. But don't use a for loop in this case. – Trevor Dixon Sep 12 '13 at 02:31

2 Answers2

1

Trevor Dixon pointed to - How to use closures. Thanks.

The problem in your code is that the callback function passed to app.get references a variable from outer scope, ie pagePath, which is changed in the next iteration of the loop. Closures are good to sort it out.

for(var i = 0; i < pages.length; i++) {
    var pagePath = "documentation/" + pages[i];

    app.get("/" + pagePath, 
        function(myPagePath){ //closure function recieving pagePath different for each iteration
            return function(request, response) { //return a new function
                jade.renderFile(myPagePath + ".jade", {}, function(err, str) { //myPagePath is a my own copy of pagePath
                if(err) throw err;
                response.send(str);
            });
        }(pagePath) //lets pass value of pagePath from current iteration
    );
}

We create a new callback function for every iteration using the 'return function' statement, which accesses myPagePath from its immediate parent scope. Refer to Trevor's link for more on closures.

robinkc
  • 1,318
  • 8
  • 12
0

Use a request parameter. http://expressjs.com/api.html#req.params

var pages = ['installation', 'gettingStarted'];

app.get('/documentation/:page', function(req, res, next) {
    var page = req.params.page;

    if (pages.indexOf(page) === -1) return next();

    jade.renderFile('documentation/' + page + '.jade', {
        pages: pages,
        nextPage: pages[pages.indexOf(page) + 1]
    }, function(err, str) {
        if(err) throw err;
        res.send(str);
    });
})
Trevor Dixon
  • 23,216
  • 12
  • 72
  • 109