I'm using connect-flash to alert some errors/warning/success messages in my login page. The problem I want to solve is to:
- Display an error message when the username doesn't exist in the database.
- Remove error once the page is reloaded
This is how I configure the app.js:
const express = require('express');
const app = express();
const session = require('express-session');
const bodyParser = require('body-parser');
const flash = require('connect-flash');
const TWO_HOURS = 1000 * 60 * 60 * 2 //T = 2 HOURS COUNTER
const {
NODE_ENV = 'development',
SESSION_LIFETIME = TWO_HOURS,
SESSION_NAME = 'session-ID',
SESSION_SECRET = 'session-Key'
} = process.env;
const IN_PROD = NODE_ENV === 'production'; //IF Node env. is production set in_prod to true
app.use(bodyParser.urlencoded({extended: true})); //Use body parser to express
app.use(bodyParser.json()); //enable reading JSON files
app.set('view engine', 'ejs'); //Allow app to use EJS files
//USE SESSION with required variables
app.use(session({
name: SESSION_NAME, //Name of the session
resave: false, //Forces the session to be saved back to the session store - NOT ENABLED
saveUninitialized: false, //Forces a session that is 'uninitialized' to be saved to the store - NOT ENABLED
secret: SESSION_SECRET, //This is a secret key used to sign the session id cookie
cookie: {
maxAge: SESSION_LIFETIME, //When the session will expire
sameSite: true, //'strict'
secure: IN_PROD //Only for https channel enabled
//domain: --(default)-- current domain
}
}));
app.use(flash()); //USE FLASH MESSAGES
const usersRouter = require('./routes/users.js'); //Import and Use : Users Router
app.use(usersRouter);
app.get('/', (req, res) => {
const {userId} = req.session; //Set new object called userId in object req.session
//const alertMessage = req.session;
return res.redirect('/user_login');
});
users.js:
router.get('/user_login', redirectHome, (req, res) => {
//console.log("LENGTH = " + req.flash("message").length);
//res.render('userEntries/login', {messages: req.flash('errorMessage')});
console.log("LENGTH = " + res.locals.msg);
res.render('userEntries/login', {messages: res.locals.msg});
});
router.post('/user_login', redirectHome, (req, res) => {
//... declaring variables (username, password) and sqlString
getConnection().query(sqlString, [username, 1], async (err, results, fields) => {
//Catch error with MySQL connection
if(err){
console.log(" > The connection with the DB have failed:\n" + err + "\n");
return res.sendStatus(500);
}
//USERNAME DOES NOT EXISTS
if(!results.length) {
console.log(" > Cannot fetch user from the database\n");
//req.flash("type", "danger");
//req.flash("intro", "ERROR!");
req.flash('errorMessage', 'Cannot find username, please try again');
res.locals.msg = req.flash("errorMessage");
console.log("#LENGTH = " + res.locals.msg);
return res.redirect('/user_login');
}
//.... more if statements below
});
});
EJS:
<% if(locals.msg) { %>
<div class="alert alert-success" style="text-align: center;">
<% locals.msg %>
</div>
<% }%>
Using the above code, will result in the following undefined scenario. The events I execute here is
- Go to '/' root
- enter invalid username and password
- submit form
CONSOLE:
::1 - GET / HTTP/1.1 302 66 - 7.120 ms
LENGTH = undefined
::1 - GET /user_login HTTP/1.1 304 - - 2.328 ms
> Cannot fetch user from the database
#LENGTH = Cannot find username, please try again
::1 - POST /user_login HTTP/1.1 302 66 - 22.432 ms
LENGTH = undefined
::1 - GET /user_login HTTP/1.1 200 5022 - 3.715 ms
Is there any particular reason why this isn't working? Is it something to do with my session configuration? I have also tried using req.flash("errorMessage") when rendering the page but also didn't work! I have also tried setting the EJS if statement to something like this (below) but also didn't work.
<% if(message.length > 0) { %>
<div class="alert alert-success" style="text-align: center;">
<%= message %>
</div>
<% } %>
UPDATE:
<% if(alertMessage.length > 0) { %>
<div class="alert alert-danger" style="text-align: center;">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>ERROR!</strong> <%= alertMessage %>
</div>
<% } %>
router.get('/user_login', redirectHome, (req, res) => {
res.locals.msg = req.flash("message");
res.render('userEntries/login', {alertMessage: res.locals.msg});
});
//POST REQUEST :
//USER DOES NOT EXISTS
if(!results.length) {
console.log(" > Cannot fetch user from the database");
req.flash("message", "The username or password are invalid, please try again!");
return res.redirect('/user_login');
}
UPDATE: See you are set the message in your post request:
res.locals.msg = req.flash("errorMessage");But on the next line, you read it also:
Remove this last line, because reading from flash will also removes the message from flash. You don't need to set to a local, since you are going to redirect.
Response locals are made for the current request. So if you set locals on post, it won't be available on the other get request. It's another request, where those locals are new.
In your get request:
Flash stores that value, you need to pass to your locals.