Search code examples
node.jsexpressconnect-flash

Trouble understanding how exactly to use connect-flash with Express 4.x?


So the basics of this is, I have a login form - if the user enters in the wrong account info, I want it to redirect back to the login page and display a message stating that they entered in the wrong information - right now I'm simply trying to output at test message to make sure I've got a working understanding of this.

I've looked high-and-low for a basic guide on understanding connect-flash (as that seems to be the tool I need for the job) but I don't exactly understand it - I've written some code to try and implement it but I keep getting this error when compiling my Jade file:

TypeError: index.jade:28
    26|       form.form-signin(method="post", action="/loginSuccess")
    27|         h2.form-signin-heading(style="text-align:center;") Please sign in
  > 28|         if loginError.length > 0
    29|             p <strong>ERROR!</strong> #{ loginError }
    30|         label.sr-only(for="inputID") Student ID
    31|         input#inputID.form-control(type="text", name="userID", placeholder="User ID", required="", autofocus="")


Cannot read property 'length' of undefined
    at eval (eval at <anonymous> (C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\lib\index.js:218:8), <anonymous>:11
4:16)
    at eval (eval at <anonymous> (C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\lib\index.js:218:8), <anonymous>:19
5:22)
    at res (C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\lib\index.js:219:38)
    at renderFile (C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\bin\jade.js:270:40)
    at C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\bin\jade.js:136:5
    at Array.forEach (native)
    at Object.<anonymous> (C:\Users\Tai\AppData\Roaming\npm\node_modules\jade\bin\jade.js:135:9)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)

My code is below, and I would greatly appreciate any help but I would love it even more if someone could explain what I did wrong (or at least link to something where I could gain an understanding of how to use connect-flash)

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var mongojs = require('mongojs');
var db = mongojs('advisingApp', ['advisingApp']);
var session = require('express-session');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');
var flash = require('connect-flash');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');


// uncomment after placing your favicon in /public
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secretString'));
app.use(
  session({
    secret: 'secretKeyCookie',
    resave: true,
    saveUninitialized: true
  })
);
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

//All custom codes go after this comment line
app.use(function (req, res) {
  // flash a message
  req.flash('info', 'hello!');
  next();
})
app.all('/test', function(req, res){
  res.send(JSON.stringify(req.flash('test')));
});
app.post("/loginSuccess", function (req, res) {
  console.log("POST Request Received");
  console.log(req.body.userID);
  console.log(req.body.userPIN);
  db.advisingApp.find({ 'studentID': req.body.userID,'PIN': parseInt(req.body.userPIN)
  }, function(err, docs) {
    if(err) {
      console.log(err);
      return err;
    }
    else if(!docs || docs.length == 0) {
      console.log("User was not found!");
      var msg = "Your username and/or password was incorrect. Please try again.";
      res.error(msg);
      res.render("/", { loginError : req.flash('info')});
    }
    else {
      console.log(docs);
      res.render("home");
    }
    //res.send(docs);
  });
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

Jade

doctype html
html(lang="en")
  head
    meta(charset="utf-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    // The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags
    meta(name="description", content="")
    meta(name="author", content="")
    link(rel="icon", href="favicon.ico")
    title Signin Template for Bootstrap
    // Bootstrap core CSS
    link(href="/stylesheets/bootstrap.min.css", rel="stylesheet")
    // Custom styles for this template
    link(href="/stylesheets/style.css", rel="stylesheet")
    // Just for debugging purposes. Don't actually copy these 2 lines!
    //if lt IE 9
      script(src="/javascripts/ie8-responsive-file-warning.js")
    // <script src="/javascripts/ie-emulation-modes-warning.js"></script>
    // HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries
    //if lt IE 9
      script(src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js")
      script(src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js")
  body
    .container
      form.form-signin(method="post", action="/loginSuccess")
        h2.form-signin-heading(style="text-align:center;") Please sign in
        if loginError.length > 0
            p <strong>ERROR!</strong> #{ loginError }
        label.sr-only(for="inputID") Student ID
        input#inputID.form-control(type="text", name="userID", placeholder="User ID", required="", autofocus="")
        label.sr-only(for="inputPIN") PIN:
        input#inputPIN.form-control(type="password", name="userPIN", placeholder="Password", required="")
        button.btn.btn-lg.btn-primary.btn-block(type="submit") Sign in
    // /container
    // IE10 viewport hack for Surface/desktop Windows 8 bug
    script(src="/javascripts/ie10-viewport-bug-workaround.js")
    //AngularJS CDN
    script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js")

Solution

  • You have several errors in your code. Please go through Express guides routing ,writing middleware and using middleware before you proceed on.

    You missed the next argument in the middleware function. And also the middleware to add flash message should be put in front of using routers. (I don't know what resources the routes router handles.)

    app.use(function (req, res, next) {
      req.flash('info', 'hello!');
      next();
    })
    
    app.use('/', routes);
    app.use('/users', users);
    

    I suspect that this middleware isn't called because of above error in code, so that the flash message is never set.

    When the response is rendered, if the flash message doesn't exist, loginError will be undefined. That's the reason you got error Cannot read property 'length' of undefined.

    res.render("/", { loginError : req.flash('info')});
    

    So in the jade template you should test loginError like this:

    if loginError
        p <strong>ERROR!</strong> #{ loginError }