Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express Middleware to populate a Jade variable for all app.get()'s

I have a Jade file that all of my templates extend called layout.jade. In it I want to be able to have a logout button if the user is currently logged in (this is kept track of in req.session).

So layout.jade will have something like,

-if (loggedin)
  a.navButton(href="/logout") Log Out

The route for a page would look something like,

app.get("/foo", function(req, res) {
    res.render("foo", {loggedin: req.session.isValidUser});
});

The thing is, I don't want to have to populate the loggedin variable manually in every single route. Is there a way I can use Express middleware to automatically set some default options for the object sent to res.render? Or is there a better method to do this?

Basically I'm asking how I can have some set of variables always sent to templates, as well as the ability to have certain custom variables available in certain templates by manually setting them in the routes.

like image 819
PherricOxide Avatar asked Sep 18 '13 22:09

PherricOxide


2 Answers

It seems this is actually a documented feature I just had trouble finding, unless anyone has a better way of doing it; From the latest Express documentation,

app.locals: Application local variables are provided to all templates rendered within the application. This is useful for providing helper functions to templates, as well as app-level data.

So in my login success function has,

req.session.username = profile.username;
app.locals.username = profile.username;

My logout function,

app.get('/logout', function (req, res) {
    delete app.locals.username;
    req.session.destroy();
    res.redirect('/login');
});

And finally in layout.jade/all of my templates,

- if(username)
  a.navButton(href="/logout") Logout
like image 159
PherricOxide Avatar answered Sep 25 '22 02:09

PherricOxide


If you set res.locals.loggedin in the /login route, as hexacyanide suggests, this local will not be available in the route for /foo. res.locals is cleared upon every request.

you could instead try placing this above other routes:

app.all('*', function(req, res, next){
  if(req.user){
    res.locals.loggedin = true;
    res.locals.currentuser = req.user;
  };
  next();
});

Pretty sure that if you modify req.user during your route, the res.locals.currentuser that you set before won't updated to be the new req.user. but not certain about that.

I actually use a custom render function for each page where I render a template, it looks like this:

function myRender(templateName){
  return function(req, res){
    res.locals.currentuser = req.user || null;
    res.render(templateName);
  };
};

and I use it like this:

app.get('/foo'
, function(req, res, next){
  res.locals.bar = req.query['bar'] || "";
  console.log('passing request to myRender middleware');
  next();
}
, myRender('foo-jade-template')
)

This has the advantage of only setting res.locals.currentuser when I am ready to render something, instead of before executing my route. So if I change req.user it is guranteed to have the most recent version at render time.

like image 38
Plato Avatar answered Sep 23 '22 02:09

Plato