jaredhanson / connect-flash

Flash message middleware for Connect and Express.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

res.locals

yuri-karadzhov opened this issue · comments

Is there a good way to pass req.flash to res.locals?

I want to have access to flash in my views and do not want to pass it every time on res.render.

I'm working on this issues as well. I think res.locals may not be the best choice because it only supports the current request/response, therefore using res.redirect will break it.

Trying app.locals gave me an 'app is undefined' error because of namespacing and I don't really want to send app as a parameter every time either.

I use such construction, but I don't like it

res.locals.helpers.flash.req = {}
res.locals.helpers.flash.req.session = req.session
res.locals.helpers.flash.req.flash = req.flash

After it I have an access to flash trough helpers.req.flash

@yuri-karadzhov @mikebarnhardt
Hi, I feel a better way to do it is adding a middleware:

app.use(flash())
app.use(function(req, res, next) {
    res.locals.messages = req.flash();
});

Then you can use messages in templates.

@MichaelJCole Yes you need to put next(); there. Sorry I made mistake there 😃

After spending way to long in this, I finally got it to work how I wanted. The key is to only call flash() before rendering the messages in the template. Otherwise, the messages get consumed on redirect or get lost if not shown in the template.

  1. use connect-flash

  2. Add a piece of middleware in server.js/app.js to add req to locals. This allows the template to call request.flash() whenever it needs. Without this, flash() gets consumed on each request/redirect defeating the purpose.

var app = module.exports = express()
  , flash=require('connect-flash');
app.configure(function(){
  ...
  app.use(express.session({ secret: "shhh" }));

  // Start Router
  app.use(flash());
  app.use(function(req, res, next) {
    res.locals.request = req;
    next();
  });

  app.use(app.router);
});
  1. Setup your route as normal (this is coffeescript, but the point here is nothing special needs to happen)
app.get '/home', (req, res) ->
  req.flash "info", "Hello World"
  res.render "#{__dirname}/views/index"
app.get '/forward', (req, res) ->
  req.flash "info", "Forwarded message!"
  res.redirect "home"
  1. Call request.flash() when you want the messages. They are consumed on each call, so don't console.log them or they'll be gone :-)
!!!
html
  head
    title= config.appTitle
    include partials/_styles

  body
    include partials/_scripts

    #header
      a(href="/logout") Logout CURRENTUSER
      h2= config.appTitle

    #messages
      - var flash = request.flash()
      each flashType in ['info','warn','error']
        if flash[flashType]
          p.flash(class=flashType)
            = flash[flashType]


    block content
      h1 content here

This is the way I started from, but I don't like to pass entire request to locals.

Hi Yuri, I also feel code is happier with logic-less templates, but the design of connect-flash is such that it decorates the request object.

In the current API, I don't see a way to access the function in Jade without passing the full request.

Yeah, you are right! It is the only way to work with redirect and back.

Well alternatively just pass the prototype of the req.flash function to your locals like so. Then you don't have to pass the whole request to your locals.

App.js

app.use(function(req, res, next) {
    res.locals.flash = req.flash;
    next();
});

layout.jade

..html..
ul
    for message in flash()
        li= message