Is there a way to render a NodeJs Express view to a variable? - node.js

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});

Related

node express how to render handlebars html page to file

I want to convert some html page to pdf via wkhtmltopdf. However, the html page I want to convert to pdf is dynamically generated using handlebars.
So I think one solution maybe to generate the html page via handlebars but to a file (html file). Then, convert that file to pdf using hkhtmltopdf, then allow the user to, somehow, download the pdf.
So, my question is: how can I render the (handlebars) dynamically generated html page to a file?
Thanks and bye ...
Simple example for create file.
var Handlebars = require('handlebars');
var source = "<p>Hello, my name is {{name}}. I am from {{hometown}}. I have " +
"{{kids.length}} kids:</p>" +
"<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>";
var template = Handlebars.compile(source);
var data = { "name": "Alan", "hometown": "Somewhere, TX",
"kids": [{"name": "Jimmy", "age": "12"}, {"name": "Sally", "age": "4"}]};
var result = template(data);
var fs = require('fs');
fs.writeFile("test.html", result, function(err) {
if(err) {
return console.log(err);
}
});
Using express-handlebars, you should use the advanced mode and create an instance of it like in this example.
The proper way would be to create a view file (like you probably already have per you question) and use the express handlebars instance to render it:
// init code
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout: 'your-layout-name',
helpers: require("path-to-your-helpers-if-any"),
});
app.engine('.file-extention-you-use', hbs.engine);
app.set('view engine', '.file-extention-you-use');
// ...then, in the router
hbs.render('full-path-to-view',conext, options).then(function(hbsTemplate){
// hbsTemplate contains the rendered html, do something with it...
});
HTH
Code above from Alex works perfect. However, my confusion was: I was using 'express-handlebars' and not 'handlebars'. Now, what I can understand is Express-Handlebars is an implementation of Handlebars for an Express application, which I´m using. I just didn't find a way to use the 'compile()' method in Express-Handlebars, so I ended up installing Handlebars (standalone) and used it to compile my (html) template and save the result to disk, just as Alex explained above.
In summary:
1) I know Express-Handlebars is Handlebars for Express app.
2) I don't know how to use "compile()" method just from express-handlebars, so I ended up installing Handlebars (from npm) and using it on the server to produce my html file (from template) and save it to disk.
3) Of course I installed and use Express-Handlebars everywhere to serve my pages in my Express app; just installed Handlebars to produce my html (in the server) with "compile()" method and save the result to disk.
Hope this is understandable. Thanks again and bye ...

Passing objects between nodejs and jade

I have the following code in my server.js
var cddata = [];
body.rows.forEach(function(doc) {
cddata.push([{id: doc.id, name: doc.key, text:doc.value.Time, group: 1}]);
});
response.render('timeline', {cddata: JSON.stringify(cddata)});
and I have the following in my Jade view file
script(src='vis/dist/vis.js')
link(rel="stylesheet", href="vis/dist/vis.css", type="text/css")
script.
//alert(cddata);
var options = {};
var data = new vis.DataSet(cddata);
var container = document.getElementById('visualization');
new vis.Timeline(container, data, options);
However, nothing related to the chart is rendered. I presume the object is not correctly passed to the jade file. Please help!
Also, is there a way to verify the incoming object in Jade? Alerts dont seem to work.
thanks
The <script> in your jade is a browser side script so won't be able to access variables in the templates generation scope. You'll need to output your data as JSON and read it in using browser side JavaScript, something like this:
script(src='vis/dist/vis.js')
link(rel="stylesheet", href="vis/dist/vis.css", type="text/css")
script.
var chartData = JSON.parse('#{cddata}')
var options = {};
var data = new vis.DataSet(chartData);
var container = document.getElementById('visualization');
new vis.Timeline(container, data, options);
After much deliberation, the following worked to pass object from node server to client side server scripting on Jade file.
on the server.js, where dbdata is an array of JSON objects
response.render('timeline', {dbdata:dbdata});
On the jade file,
script.
var chartData = !{JSON.stringify(dbdata)};
Thanks,

Retrieving HTML from CouchBase into Node.js / Express 4 leaves it unrendered

I'm having a small issue with rendering HTML, stored in CouchBase, fetched by Node.js
In CouchBase I have several small HTML-snippets. They contain text, tags such as <br /> and html entities such as <. They are of course stored as an escaped string in JSON.
So far, so good. However when I pull it out and display on the page, it is rendered "as-is", without being interpreted as HTML.
For example:
[ some content ...]
<p>Lorem is > ipsum<br />And another line</p>
[rest of content ...]
From the controller in Express 4:
var express = require('express');
var router = express.Router();
var couchbase = require('couchbase');
var cluster = new couchbase.Cluster('couchbase://myserver');
var bucket = cluster.openBucket('someBucket', 'somePassword');
var Entities = require('html-entities').XmlEntities;
entities = new Entities();
var utf8 = require('utf8');
/* GET home page. */
router.get('/', function(req, res) {
bucket.get('my:thingie:44', function(err, result) {
if(err) throw err
console.log(result);
var html = utf8.decode(entities.decode(result.value.thingie.html));
// var html = utf8.encode(result.value.thingie.html);
// var html = utf8.decode(result.value.thingie.html);
res.render('index', { title: 'PageTitle', content: html });
});
});
It is then passed to the template (using hogan.js) for rendering.
When looking into this I found that it might have something to do with the encoding of the <'s and <'s that prevent it from being parsed. You can see my converting attempts in the code, where none of the options gave the desired result, i.e. rendering the contents as HTML.
When using utf8.decode(), no difference.
Using utf8.encode(), no difference.
Using entities.decode() it convert < into < as predicted, but it's not rendered even if <div;&gt becomes <div>.
Any ideas?
I found the solution over here: Partials with Node.js + Express + Hogan.js
When putting HTML in a Hogan template, you have to use {{{var}}} instead of {{var}}.
And thus it renders beautifully, as intended :)
Wasn't encoding issues at all ;)

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 Express.js, how can I render a Jade partial-view without a "response" object?

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'});

Resources