In Express.js, how can I render a Jade partial-view without a "response" object? - node.js

Using Express.js, I'd like to render a partial-view from a Jade template to a variable.
Usually, you render a partial-view directly to the response object:
response.partial('templatePath', {a:1, b:2, c:3})
However, since I'm inside a Socket.io server event, I don't have the "response" object.
Is there an elegant way to render a Jade partial-view to a variable without using the response object?

Here's the straight solution to this problem for express 3 users (which should be widely spread now):
res.partial() has been removed but you can always use app.render() using the callback function, if the response object is not part of the current context like in Liors case:
app.render('templatePath', {
a: 1,
b: 2,
c: 3
},function(err,html) {
console.log('html',html);
// your handling of the rendered html output goes here
});
Since app.render() is a function of the express app object it's naturally aware of the configured template engine and other settings. It behaves the same way as the specific res.render() on app.get() or other express request events.
See also:
http://expressjs.com/api.html#app.render for app.render()
https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x for express 2.x > 3.x migration purposes

You can manually compile the Jade template.
var jade = require('jade');
var template = require('fs').readFileSync(pathToTemplate, 'utf8');
var jadeFn = jade.compile(template, { filename: pathToTemplate, pretty: true });
var renderedTemplate = jadeFn({data: 1, hello: 'world'});

Related

What doesn't nodejs relate 'this' as the object that encapsulates the function?

I wrote the following code in nodejs:
var express = require('express');
var app = express();
app.message = "helloworld";
app.get('/check', function (req,res) {
res.end("GET request OK");
console.log(this.message);
});
app.listen(4000);
When I run the code and send a GET request, the line:
console.log(this.message);
prints "undefined".
However, when I change it to:
console.log(app.message)
I get "helloworld".
I thought that this variable should represent the object that invoked the function. If so, why doesn't this object include the attribute .message ?
this can be whatever the author of the library intends it to be. It could be the app instance or it could be the global object.
In this case, it appears it's the global object.
As a sidenote too, it's not recommended to add expando properties to an existing library like that.

Is there a way to render a NodeJs Express view to a variable?

Is there a way to render an express view to a variable as opposed to the response stream?
var view = path.join( __dirname, '/../customer-product/views/copysheet.html');
res.render( view, {
data: product
})
I need the html on the server side so that I can be passed to PhantomJs for PDF generation.
There's a pretty good article on it at Strongloop. The upshot is that you would interact directly with the view engine like so:
var templatePath = require.resolve('./copysheet.html');
var templateFn = require('jade').compileFile(templatePath); // or whatever view engine you're usingg
var output = templateFn({data:product});

How can I bootstrap models from express js into backbone at page load?

I have some data in a mongodb database and want to pass it to a backbone collection when I load the home page. One way of doing this would be to set up a node route like this:
exports.index = function(req, res){
db.users.find(function(err, docs) {
var docs_string = JSON.stringify(docs);
res.send(docs_string);
};
};
But this won't work because it won't render my jade template that pulls in the backbone code, it simply shows the JSON in plain text.
Alternatively, I could render my jade template passing in the data as a variable to jade:
exports.index = function(req, res){
db.users.find(function(err, docs) {
var docs_string = JSON.stringify(docs);
res.render('index', {
title: "Data",
docs_string: docs_string
})
});
};
Then in the jade template, have a script like this to add the users to my user collection:
script
var docs = !{docs_string};
var users = new app.Users();
_.each(docs, function(doc) {
var user = new app.User(doc);
users.add(user);
})
But this seems wrong, since I don't really want to pass the data to the jade template, I want to pass it to a backbone collection. Also, with this solution I don't know how to then include an underscore template (on the backbone side of things) into the page rendered by jade on the server side.
What is the standard way of passing data from a node server to a backbone collection?
Assuming your data is an object, you should convert it to string using JSON.stringify() and then insert in a page inside script tag, so your resulting HTML looks like this (I don't use Jade):
<script>
var data = {...}; // in template instead of {...} here should be the instruction to insert your json string
</script>
Then when the page loads, your script will be executed and the data will be available as a global variable in the browser so you can initialise backbone collection using it. This all is a good idea only to bootstrap your data on the first page load (to avoid extra request) and then use API to request data for this and other pages.
Check out Steamer, a tiny node / express module made for this exact purpose.
https://github.com/rotundasoftware/steamer

In nodejs & express, what's the difference between settings & locals

Starting my way in node + express, what's the difference between:
app.set(key, value)
and
app.locals({key: value});
I've read the express docs and it states that app.locals are passed to all the rendered views, but I was also able to access the settings from a jade view as well (using #{settings.someKey}).
As both are available in jade templates I can't seem to figure out what the difference or different usage for the 2.
The difference is that by manipulating app.locals directly, you can create 'top level' variables for your templates, instead of having to use the settings. prefix.
app.set(key, value) is the same as app.locals.settings[key] = value; the former is the preferred way of configuring certain parts of Express (like setting view engine).
EDIT: small demo to show how they do the same:
var app = require('express')();
app.set('foo', 'bar');
console.log('app.get("foo"):', app.get('foo')); // 'bar'
console.log('app.locals.settings.foo:', app.locals.settings.foo); // 'bar'
app.locals.settings['foo'] = 'another bar';
console.log('2nd app.get("foo"):', app.get('foo')); // 'another bar'

Is it OK to add data to the response object in a middleware module in Express.js?

Here's the basic setup. I'm trying to create a simple middleware component that would allow me to easily pass data from my route directly to my javascript in the client side. (Very similiar to the Gon gem in ruby). The way I'm doing it is by having a module that looks like this:
module.exports = function(){
return function(req,res,next){
var app = req.app;
if(typeof(app) == 'undefined'){
var err = new Error("The JShare module requires express");
next(err);
return;
}
res.jshare = {};
app.dynamicHelpers({
includeJShare: function(req,res){
if(typeof(res.jshare) === 'undefined'){
return "";
}
return function(){
return '<script type="text/javascript">window.jshare=' + JSON.stringify(res.jshare) + '</script>';
}
}
});
next();
};
}
Then, in my route I can do this:
exports.index = function(req, res){
res.jshare.person = {firstName : "Alex"};
res.render('index', { title: 'Express' })
};
Finally in the layout.jade:
!{includeJShare()}
What that does is in outputs a line of javascript on the client that creates the exact JSON object that was created server side.
Here's the question; it all works as expected, but being new to Express and Node.js in general, I was just curious if attaching properties onto the response object is OK, or is there something wrong with doing it that I'm simply overlooking? For some reason it doesn't pass my "smell test" but I'm not sure why.....
I know this is an old thread, but there is something else to add to this topic.
Express has a response.locals object which is meant for this purpose - extending the response from middleware to make it available to views.
You could add a property directly to the response object, and as #hasanyasin indicated, is how JavaScript is designed. But Express, more specifically, has a particular way they prefer we do it.
This may be new in express 3.x, not sure. Perhaps it didn't exist when this question was asked.
For details, see
http://expressjs.com/en/api.html#res.locals
There is also an app.locals for objects which don't vary from request to request (or response to response I suppose).
http://expressjs.com/en/api.html#app.locals
See also: req.locals vs. res.locals vs. res.data vs. req.data vs. app.locals in Express middleware
It is perfectly OK. It is how JavaScript is designed. Only thing you should be careful is to not accidentally overriding already existing properties or being overridden by others. To be safer, instead of adding everything directly to req/res objects, you might consider going a level deeper:
res.mydata={}
res.mydata.person= ...
Like that.
Use res.locals for including custom variables in your response object.

Resources