Reputation: 638
I'm new to node and trying to show validation errors (using express-validator and express 4) when a user tries to submit a form.
The validator seem to work since if I log the data to console everything is as expected. However, I cannot display the errors on the page when I render the view (nothing is displayed). The only difference with the "standard" tutorials I have been following on express validation, is that I'm posting the data with AJAX.
My code is below. I use [...] to indicate that there is more code I removed, and I stripped down some of the form fields for brevity.
app.js
var express = require('express')
, indexController = require('./routes/index')
, membersController = require('./routes/members')
[...]
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, expressValidator = require('express-validator');
var app = express();
[...]
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressValidator()) // tried both placing it here or below
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// I realize this may be not optimal
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', indexController);
app.use('/members', membersController);
[...]
module.exports = app;
handle_members.js
$(document).ready(function() {
$('#join_btn').click(function(event, req, res){
event.preventDefault();
var newMember = {
'name': $('#join_form input#join_name').val(),
'email': $('#join_form input#join_email').val()
}
$.ajax({
type: 'POST',
data: newMember,
url: '/members/addmember',
dataType: 'JSON'
}).done(function(response){
if (response.msg === 'success'){
alert('New member added successfully!')
}
// maybe this is not necessary?
else if (response.msg === 'validation'){
alert('validation failed');
}
else{
alert('Error: ' + response.msg)
}
});
});
});
members.js
var express = require('express');
var router = express.Router();
router.post('/addmember',validator, function(req, res) {
var db = req.db;
var collection = db.get('memberstest');
collection.insert(req.body, function(err, result){
res.send(
(err === null) ? { msg: 'success' } : { msg: err }
);
});
});
function validator(req, res, next) {
req.checkBody('email', 'not valid email').isEmail();
req.checkBody('name', 'cannot be empty').notEmpty();
var errors = req.validationErrors();
if (errors) {
console.log(errors) // these are as expected
res.render('index',{errors:errors}); // no errors displayed
}
else {
next();
}
};
module.exports = router;
index.jade
[...]
form#join_form(method='POST', action='', role='form')
div.form-group
input#join_name.form-control(type='text', name='join_name')
input#join_email.form-control(type='email', name='email')
button#join_btn.btn(type='button') join
if errors
ul
for error in errors
li = error.msg
[...]
The errors variable when logged to console looks like this:
[ { param: 'email', msg: 'not valid email', value: 'xxxx' }, { param: 'name', msg: 'can't be empty', value: '' } ]
In the past couple of days I really tried a lot of different things but none of them worked. The problem seem to be always the same: all good but when I render the view is like it never enters the "if errors ..." statement. Maybe there is something very basic I'm missing here? Any help is greatly appreciated, thank you.
PS. Eventually the form ideally should be inside a modal/pop-up, in case that changes something.
Upvotes: 1
Views: 2085
Reputation:
Try to add the validator middleware immediately after any of the bodyParser middlewares, like the documentation asks to:
var express = require('express')
, indexController = require('./routes/index')
, membersController = require('./routes/members')
[...]
, cookieParser = require('cookie-parser')
, bodyParser = require('body-parser')
, expressValidator = require('express-validator');
var app = express();
[...]
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressValidator()); // this line must be immediately after any of the bodyParser middlewares!
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// I realize this may be not optimal
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', indexController);
app.use('/members', membersController);
[...]
module.exports = app;
Based on the documentation, errors seems to be an array of objects with the msg
and param
properties. Try to update your jade code to the following:
ul
if errors
each error, i in errors
li #{error.msg}
After analyzing the code that the OP provided me through Github, I found the problem. The OP is sending the data to the backend using an Ajax call, and responding it using res.render, which is clearly wrong, since res.render
isn't to respond requests made with Ajax, the right method to do this is res.json.
Example:
Call /addmember
endpoint using jQuery:
var data = {}; // data here
$.ajax({
type: 'POST',
data: data,
url: '/addmember',
dataType: 'JSON'
}).done(function() {
alert('done');
}).fail(function() {
alert('fail');
});
Answer it from the backend using res.json
:
router.post('/addmember', (req, res) => {
var db = req.db;
var collection = db.get('memberstest');
collection.insert(req.body, (error, result) => {
if (error)
return res.json({ error });
return res.json({ result });
});
});
Upvotes: 1