2

With an express app running on a node server, how would I go about recursively searching for a render file from the full path right back to the beginning of the supplied URL.

For example, if someone was to hit my server with www.somewebsite.com/shop/products/product, the render engine would first check that there is an index.jade file in shop/products/product/. If none is found it would then check shop/products/, and subsequently shop/.

var express = require('express');

var app = express();

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

    res.render(req.path + '/index.jade', function(err, html){

        // some loopback code which alters the path and recalls the render method    

    })
});

The problem is that the response object is not passed to the render callback, so I'm unable to recall render on the response. I'm looking to create a loop because the URL paths may be any number of directories deep, so I can't just assume I only need to cascade for a definitive number of times.

Anyone see a way round this?

shennan
  • 10,798
  • 5
  • 44
  • 79

1 Answers1

0

You should be able to use the response object from the closure. I think (assuming express allows you to call res.render a second time) you could use code like this answer to achieve what you want:

var express = require('express');

var app = express();

app.get('/*', tryRender);

function tryRender(req, res){

    res.render(req.path + '/index.jade', function(err, html){

        if (err) {
            req.path = 'mynewpath';
            tryRender(req, res);
        }    

    })
}

Note: You will need to add a base case or this function will recurse infinitely if it doesn't find a view that works :D

In the event that express doesn't allow a subsequent call to res.render, you'll probably need to find out if the file exists on the file system yourself.

Ryan Endacott
  • 8,772
  • 4
  • 27
  • 39
  • Using a closure won't work because the callback will need to be called a variable number of times depending on how many parts to the url there are. Your example uses redirects which I want to avoid. – shennan Jun 05 '13 at 16:45
  • As long as express allows subsequent `res.render` calls, that code should work. The example was a quick one I could find. Just substitute the `res.redirect` for `res.render`. Anyway, I added a code example of what I meant. If express doesn't allow you to call render multiple times, then you'll probably have to do something with the file system to check if the view exists. – Ryan Endacott Jun 05 '13 at 16:51
  • I think my recursive function should deal with the issue of closures not working, if I understood what you meant. Keep in mind, you will need a base case or this will loop infinitely :D – Ryan Endacott Jun 05 '13 at 17:01
  • 1
    It's looking like I've been underestimating closures again. I didn't think to pass the looping method into the express.get method. That will probably work! But am unable to test right now so will mark you as correct tomorrow morning when I'm back at my development machine. Thanks in advance if this solves the problem. – shennan Jun 05 '13 at 17:10
  • Yup, closures can be pretty awesome! And no problem - I hope it works! – Ryan Endacott Jun 05 '13 at 17:37
  • It does indeed work, though to get it working the code did need a little tweaking - either a global variable (yuk) or another closure to store the changing path names. Req.path seems like it is read-only so it can't be used to change the location of our jade file as we step through. – shennan Jun 11 '13 at 09:42
  • Interesting. I'm glad it worked out though! Maybe you could use another property of `req` that you set yourself. You would just have to check that it's null for the first call. E.g. `req.customPath = 'mynewpath'` and then read from it on subsequent calls: `var path = req.customPath || req.path;` This is assuming that all of req isn't readonly. – Ryan Endacott Jun 11 '13 at 15:00