0
votes

I've recently began working on my first Express project and I chose to use Handlebars as my template language because I had some prior experience when creating Ghost blog themes.

I'm creating a login screen using Passport.js and connect-flash to send error messages to the user. I'm able to pass in the error messages as a handlebars helper just fine but when I attempt to include an if statement inside the handlebars template it is always false even when there is an error message.

Here's my code:

login.js (route)

app.route('/login')
    .get(function(req, res) {
        if (req.isAuthenticated()) {
            res.redirect('/');
        } else {
            res.render('login', {
                helpers: {
                    message: req.flash('loginMessage')
                }
            });
        }
    })
    .post(...);

login.handlebars

<form action="/login" method="post">
    <div>
        <label>Email</label>
        <input type="text" name="email">
    </div>
    <div>
        <label>Password</label>
        <input type="password" name="password"> 
    </div>
    <button type="submit">Log In</button>
</form>

{{#if message}}
    <p style="color: red">{{message}}</p>
{{/if}}

This works without the if statement:

<p style="color: red">{{message}}</p>

But I don't like the idea of having empty elements all over my html. Any help would be greatly appreciated as I'm sure I'm missing something very simple.

Thanks.

2

2 Answers

1
votes

I believe you must use a subexpression in order to invoke multiple helpers within a single mustache. The fix is as simple as adding parentheses:

{{#if (message)}}
    <p style="color: red">{{message}}</p>
{{/if}}

Edit

Note that the above assumes that the type of object at helpers.message is a function as the Handlebars documentation states that helpers are functions. However, the connect-flash documentation suggests that req.flash('loginMessage') will return an array. In this case, the result should not be assigned to a helper, but should be a regular value of the view model object:

res.render('login', {
    messages: req.flash('loginMessage')
});

Within our template, as messages is an array, we will have to lookup and access its 0th element:

{{#if (lookup messages 0)}}
    <p style="color: red">{{messages.[0]}}</p>
{{/if}}
0
votes

This is probably coming way toooooo late, but for those who will still encounter this or related problem in the future, I hope this works for you. Another way you could do it is to use res.redirect('/login'); instead of res.render('login).

Add this to your SERVER/INDEX.JS

const flash = require('connect-flash');//import this guy
    app.use(flash());
    app.use(function(req, res, next) {
    res.locals.message = req.flash('loginMessage'); 
    next();
  });

Your LOGIN.JS will look like this

  app.route('/login')
   .get(function(req, res) {
     if (req.isAuthenticated()) {
        res.redirect('/');
        return;//you should always return if there's no more thing to do
     } else {
       req.flash('loginMessage', 'your message here');
       res.redirect('/login');
       return;//you should always return if there's no more thing to do
    };
  })
  .post(...);

The above approach makes it easier for you to reuse your messages. Eg., You can reuse the above message by just changing req.flash('loginMessage', 'your message here'); to this req.flash('loginMessage', 'another message here'); .

You can also reuse the entire message by moving all error and success messages inside a PARTIAL folder and then using it in all your other pages in your front-end by inserting this {{>yourMessages}} in all the pages.

your LOGIN.handlebars

 <form action="/login" method="post">
   <div>
    <label>Email</label>
    <input type="text" name="email">
   </div>
   <div>
    <label>Password</label>
    <input type="password" name="password"> 
   </div>
   <button type="submit">Log In</button>
 </form>

 {{#if message}}
  <p style="color: red">{{message}}</p>
 {{/if}}