ExpressJS 3.0 How to pass res.locals to a jade view? - node.js

I want to display a flash message after a user fails to sign in but I just can't get the variables to show up in my Jade views.
I have some pieces, I know I have to use this in my app.configure():
app.use (req, res, next) ->
res.locals.session = req.session
And I'll set what the flash message is after the user POSTS the wrong password:
exports.postSession = (req, res) ->
users = require '../DB/users'
users.authenticate(req.body.login, req.body.password, (user) ->
if(user)
req.session.user = user
res.redirect(req.body.redirect || '/')
else
req.session.flash = 'Authentication Failure!'
res.render('sessions/new', {title:'New', redirect: req.body.redirect })
)
I don't know how to access res.locals.session in my Jade file. I doubt I am setting everything up right. This question is a lot like this one: Migrating Express.js 2 to 3, specifically app.dynamicHelpers() to app.locals.use? but I still can't get it to work. It would be much appreciated if someone could show me just a simple example of setting values in res.local and accessing them in a view.
p.s. I do know about connect-flash but I need to understand how to make things available in views.
This is my app:
app.configure(() ->
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.bodyParser())
app.engine('.jade', require('jade').__express)
app.use(express.methodOverride())
app.use(express.cookieParser())
app.use(express.session({ store: new express.session.MemoryStore({reapInterval: 50000 * 10}), secret: 'chubby bunny' }))
app.use(express.static(__dirname + '/public'))
app.use((req, res, next) ->
res.locals.session = req.session
next()
)
app.use(app.router)
)

Just to give a short summary for everyone who has the same problem and got the impression that is was solved changing res.redirect.
It is very important to put your app.use middleware before app.router. See the comments by TJ Holowaychuck, the author of express
https://groups.google.com/d/msg/express-js/72WPl2UKA2Q/dEndrRj6uhgJ
Here is an example using a fresh installation of express v3.0.0rc4
app.js:
app.use(function(req, res, next){
res.locals.variable = "some content";
next();
})
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
index.jade:
extends layout
block content
h1= title
p Welcome to #{title}
p= variable

If you are using express.session() you must call your function AFTER express.session() but BEFORE app.router, inside of app.configure().
app.js
app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session());
// Give Views/Layouts direct access to session data.
app.use(function(req, res, next){
res.locals.session = req.session;
next();
});
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
index.jade
extends layout
block content
h1= title
p My req.session.var_name is set to #{session.var_name}

Related

res.locals in app.use not working, but sending options on res.render does

Pug file:
...
- var paths = flatSitemap(sitemap);
app.js file:
var fsm = require('./routes/fsm.js');
app.set('port', process.env.PORT || 4109);
app.set('views', path.join(__dirname, 'src/pug'));
console.log(path.join(__dirname, 'src/pug'));
app.set('view engine', 'pug');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(function (req, res, next) {
res.locals.flatSitemap = fsm.flatSitemap;
next();
});
app.locals.flatSitemap = fsm.flatSitemap;
app.get('/', function(req, res) {
res.render('./index', {flatSitemap: fsm.flatSitemap}); // works!!!
res.render('./index'); // Not working
});
So when I use the res.render using the options it works, but if I don't include the options and rely on pug reading res.locals it doesn't, and comes back with "flatSitemap is not a function".
The res object is not automatically passed to the view. Hence the message that flatSitemap does not exist or is not a function. You won't get around appending it as a parameter. You can make a condition with a binary logic OR operator.
app.get('/', function(req, res) {
res.render('./index', { flatSitemap: res.locals.flatSitemap || fsm.flatSitemap });
});

Using routes with requirejs on the server side

I'm tinkering with server side requirejs and I have a problem with routes. My routes/index.js file has:
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: 'Express' });
};
});
and in my server.js I have:
define(['express', 'module', 'path', './routes'],
function (express, module, path, routes) {
var app = express();
app.configure(function() {
// all environments
var filename = module.uri;
app.set('port', process.env.PORT || 3000);
app.use(express.static(path.dirname(filename) + '/views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(express.static(path.dirname(filename) + '/public'));
});
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.index);
return app;
});
When I run this I get the following error:
500 Error: Failed to lookup view "index"
at Function.app.render (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/application.js:489:17)
at ServerResponse.res.render (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/response.js:755:7)
at exports.index (/Users/johnwesonga/backbonejs/src/helloworld/routes/index.js:7:9)
at callbacks (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/router/index.js:161:37)
at param (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/router/index.js:135:11)
at pass (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/router/index.js:142:5)
at Router._dispatch (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/router/index.js:170:5)
at Object.router (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/lib/router/index.js:33:10)
at next (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/node_modules/connect/lib/proto.js:190:15)
at next (/Users/johnwesonga/backbonejs/src/helloworld/node_modules/express/node_modules/connect/lib/middleware/session.js:313:9)
Any clue where i'm going wrong?
It could be simply that something has been cached or needs to be restarted.
Unfortunately I don't have a definitive answer, but I was having a similar problem: everything seemed to be set up correctly however I was getting an error saying that it couldn't find the view. I gave up, switched off the computer then came back to it the next morning.....and it worked.
I hope this provides a clue for anyone looking at this post, (as I did), in the future

Express validation error with express-validator

I want to use express-validator in my app.
Here is my app.js code:
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.logger('dev'));
app.use(express.methodOverride());
app.use(app.router);
app.use(express.bodyParser());
app.use(express.urlencoded());
app.use(express.json());
app.use(expressValidator());
Below is my route:
module.exports = function(app) {
app.post('/login', userController.login);
}
And here is my code for login:
exports.login = function(req, res, next) {
req.assert('email', 'Email not valid').isEmail();
var errors = req.validationErrors();
if (errors) {
return res.redirect('/login');
}
passport.authenticate('local', function(err, user, info) {
// do stuff
})(req, res, next);
};
When I try to post something to /login I got the follwoing error message :
TypeError: Object # <IncomingMessage> has no method 'assert'
I saw that this might be related to an issue with app.use but right now i'm stuck...
EDIT 1 :
I change my app.use to those ones, but it doesn't solve my issue:
app.use(express.logger('dev'));
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(express.urlencoded());
app.use(express.json());
app.use(expressValidator());
app.use(app.router);
You should use app.router only after any middleware that you're going to use in your routes:
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(express.urlencoded());
app.use(express.json());
app.use(expressValidator());
app.use(app.router);
The reason is that the order in which you declare middleware with Express is very important: if you add app.router before expressValidator, it means, that the router middleware will get to handle requests before the validator middleware is even called and got a chance to add its magic to req.
I had the same issue! your app.js and route.js code are just fine, but in your code for login, you have to change from:
req.assert('email', 'Email not valid').notEmpty();
and replace it for:
req.check('email', 'Email not valid').notEmpty();
If you see the code https://github.com/ctavan/express-validator/blob/master/lib/express_validator.js on line 198, assert is only an alias for check. And seems to have an issue with that name "assert", maybe confuses nodejs because there is a module called "assert", is only a guess.
Anyway, seems to work just fine with it.
Hope it helps!
Kindly check by replacing assert with checkBody.
req.checkBody('email', 'Email not valid').notEmpty().
Do it like this.

res.locals returned undefined

I'm trying to set some response-specific variables, and I'm getting undefined for res.locals when I log it from within my middleware, but it returns the function just fine if I log it from within a route function.
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(function (res, req, next) {
console.log("res.locals from app.use middleware: ", res.locals);
// res.locals.boom = 'nice';
// res.locals.zoom = 'yeah!';
next();
});
app.use(app.router);
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
Any ideas?
You have your request & response objects backwards. Obviously if you know the difference in your code, naming doesn't matter, but best to keep things named correctly.
app.use( function (request, response, next) {
// stuff
});
I can't recall off the top of my head, but I believe you want:
request.app.locals;
using my example above. Again, not 100% sure. You can always console out the request object to check.
The app.locals object is a JavaScript Function, which when invoked with an object will merge properties into itself, providing a simple way to expose existing objects as local variables.
app.locals({
title: 'My App',
phone: '1-250-858-9990',
email: 'me#myapp.com'
});
app.locals.title
// => 'My App'
app.locals.email
// => 'me#myapp.com'

express without a template

Is there a reason why I should avoid doing this?
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set("view options", {layout: false});
app.use(express.static(__dirname + '/views'));
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
var html_dir = './views/';
app.get('/', function(req, res){
res.sendfile(html_dir + "login.html");
});
you need to use res.write and res.end() and just read the content's of the file vis the core require('fs') you can use res.set(field, [value]) for the headers
full docs

Resources