NodeJS, Express - Render EJS view to a download file - node.js

I have a NodeJS, Express 3 app that uses EJS templating. I have a route that enables 'preview' of some form fields containing HTML and CSS that are posted. It simply plugs them in and renders my preview.ejs template like this..
app.post('/preview', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
res.render('preview',{_layoutFile:'', htm:htm, css:css});
});
What I'd like to do now is a similar route that forces download of the file instead..
app.post('/download', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
// res.download or res.sendfile here ??
});
I see that there is a res.sendfile() and res.download(), but how can I use these with my EJS 'preview' view template?
P.S. - I'm also using Mikeal's request is this same app. I wonder if there is a way I could use pipe to fs (filesystem) and then force download of the saved file?

See: http://expressjs.com/api.html#res.attachment
res.attachment() sets Content-Disposition: attachment header which tells the browser to treat the response as a download.
app.post('/download', function(req, res){
var htm = req.body.htm;
var css = req.body.css;
res.attachment();
res.render('preview',{_layoutFile:'', htm:htm, css:css});
});

Related

template layout for PugJs

I used NodeJs with Handlebars and thought about switching to PugJs because some functionality is native - using Handlebars requires some helper functions / partials.
In Handlebars I have to define a layout and pass in the template. In PugJs I created two example routes
First route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Home',
template: 'main'
});
});
module.exports = router;
Second route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Page2',
template: 'pageTwo'
});
});
module.exports = router;
As you can see I always have to render my index file and pass in the desired pug file as a template variable.
index.pug
doctype html
html
include ./header.pug
body
include ./templates/#{template}.pug
header.pug
head
title #{title} template!
main.pug
script(src='./client/main.js')
h1 main content here
pageTwo.pug
p pageTwo
When rendering the pug files I get this error
ENOENT: no such file or directory, open
'...\views\templates\#{template}.pug'
How can I replace #{template} with the correct template variable?
Dynamic template selection isn't a feature of pug, I believe it has something to do with how pug pre-compiles everything into a JavaScript function that stays in-memory inside node.js when it runs. The benefit of that is super-fast page rendering, so we're happy to keep using pug and just work around this.
Speaking of which, you can accomplish what you want to do using conditional logic:
doctype html
html
include ./header.pug
body
if template === 'pageOne'
include ./templates/pageOne.pug
else if template === 'pageTwo'
include ./templates/pageTwo.pug
else
include ./templates/home.pug
You should also look into the extends feature to simplify adding the header into your templates and mixins to resuse code between templates. You might find that these features could provide a better solution to your requirements with some redesign.

Load templates from existing file

I'm using Handlebars in my NodeJS application as my templating engine.
I've put all my templates in a views folder like so :
-
- /controllers
- /views
- index.html
- server.js
Here's my code to render the template when the user access a given URL (using express for routing) :
app.get("/", function(req, res){
var template = handlebars.compile("views/index.html");
var data = {"name": "Charles"};
var result = template(data);
res.send(result);
});
I'm trying to render a template from a file, but it's not working. This is what the browser outputs directly when I'm accessing the / URL :
views/index.html
That makes sense, since it's interpreting the given param as a string directly and not as a path to an external template.
How can I load my template file (in this case the one in views/index.html to a variable, so that I can then render the template?
The only examples I found were storing all the templates in a file and loading them via AJAX, but all these examples were from "front-end" handlebars and not when using it with Node.
Is it possible to achieve what I want? I looked at the documentation but it's hard to find good infos for handlebars with NodeJS.
From your description, it sounds like you want handlebars as view engine, with dynamic views. You don't need to do this manually, here is an example (using express-handlebars):
var handlebars = require('express-handlebars');
app.engine('.html', handlebars({layout: false, extname: '.html'}));
app.set('view engine', '.html');
app.get("/:view", function(req, res){
var view = req.params.view;
res.render(view, { "name": "Charles" }); // Whatever data you want
});
With handlebars you have to load the file yourself or you can precompile the files (using grunt/gulp maybe) I feel way more confortable with swig ( http://paularmstrong.github.io/swig/ )
It is very simple to use. And it has also integration with express if you want.
var swig = require('swig');
swig.renderFile('/path/to/template.html', {
pagename: 'awesome people',
authors: ['Paul', 'Jim', 'Jane']
});
In your case
app.get("/", function(req, res){
res.send(swig.renderFile('views/index.html', {"name": "Charles"}));
});

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 ...

How to serve rendered Jade pages as if they were static HTML pages in Node Express?

Usually you render a Jade page in a route like this:
app.get('/page', function(req, res, next){
res.render('page.jade');
});
But I want to serve all Jade pages (automatically rendered), just like how one would serve static HTML
app.use(express.static('public'))
Is there a way to do something similar for Jade?
"static" means sending existing files unchanged directly from disk to the browser. Jade can be served this way but that is pretty unusual. Usually you want to render jade to HTML on the server which by definition is not "static", it's dynamic. You do it like this:
app.get('/home', function (req, res) {
res.render('home'); // will render home.jade and send the HTML
});
If you want to serve the jade itself for rendering in the browser, just reference it directly in the url when loading it into the browser like:
$.get('/index.jade', function (jade) {
//...
});
https://github.com/runk/connect-jade-static
Usage
Assume the following structure of your project:
/views
/partials
/file.jade
Let's make jade files from /views/partials web accessable:
var jadeStatic = require('connect-jade-static');
app = express();
app.configure(function() {
app.use(jadeStatic({
baseDir: path.join(__dirname, '/views/partials'),
baseUrl: '/partials',
jade: { pretty: true }
}));
});
Now, if you start your web server and request /views/partials/file.html in browser you
should be able see the compiled jade template.
Connect-jade-static is good, but not the perfect solution for me.
To begin with, here are the reasons why I needed jade:
My app is a single page app, there are no HTMLs generated from templates at runtime. Yet, I am using jade to generate HTML files because:
Mixins: lots of repeated / similar code in my HTML is shortened by the use of mixins
Dropdowns: I know, lots of people use ng-repeat to fill the options in a select box. This is a waste of CPU when the list is static, e.g., list of countries. The right thing to do is have the select options filled in within the HTML or partial. But then, a long list of options makes the HTML / jade hard to read. Also, very likely, the list of countries is already available elsewhere, and it doesn’t make sense to duplicate this list.
So, I decided to generate most of my HTML partials using jade at build time. But, this became a pain during development, because of the need to re-build HTMLs when the jade file changes. Yes, I could have used connect-jade-static, but I really don’t want to generate the HTMLs at run time — they are indeed static files.
So, this is what I did:
Added a 'use' before the usual use of express.static
Within this, I check for the timestamps of jade and the corresponding html file
If the jade file is newer, regenerate the html file
Call next() after the regeneration, or immediately, if regeneration is not required.
next() will fall-through to express.static, where the generated HTML will be served
Wrap the ‘use’ around a “if !production” condition, and in the build scripts, generate all the HTML files required.
This way, I can also use all the goodies express.static (like custom headers) provides and still use jade to generate these.
Some code snippets:
var express = require('express');
var fs = require('fs')
var jade = require('jade');
var urlutil = require('url');
var pathutil = require('path');
var countries = require('./countries.js');
var staticDir = 'static'; // really static files like .css and .js
var staticGenDir = 'static.gen'; // generated static files, like .html
var staticSrcDir = 'static.src'; // source for generated static files, .jade
if (process.argv[2] != 'prod') {
app.use(‘/static', function(req, res, next) {
var u = urlutil.parse(req.url);
if (pathutil.extname(u.pathname) == '.html') {
var basename = u.pathname.split('.')[0];
var htmlFile = staticGenDir + basename + '.html';
var jadeFile = staticSrcDir + basename + '.jade';
var hstat = fs.existsSync(htmlFile) ? fs.statSync(htmlFile) : null;
var jstat = fs.existsSync(jadeFile) ? fs.statSync(jadeFile) : null;
if ( jstat && (!hstat || (jstat.mtime.getTime() > hstat.mtime.getTime())) ) {
var out = jade.renderFile(jadeFile, {pretty: true, countries: countries});
fs.writeFile(htmlFile, out, function() {
next();
});
} else {
next();
}
} else {
next();
}
});
}
app.use('/static', express.static(staticDir)); // serve files from really static if exists
app.use('/static', express.static(staticGenDir)); // if not, look in generated static dir
In reality, I have a js file containing not just countries, but various other lists shared between node, javascript and jade.
Hope this helps someone looking for an alternative.

Passing Variable from NodeJS to client-side JS file

Is it possible to pass a server-side JavaScript variable to a <script> tag in an HTML view?
In my routes file I have:
exports.index = function(req, res){
res.sendfile('views/index.html', {
data: {foo: bar}
});
};
If I was using a Jade template, I could do:
script(type='text/javascript').
var local_data =!{JSON.stringify(data)}
To access the data object. However, that doesn't work for an html file. Is there a work-around for this?
Have a route send the data using res.json() and use AJAX in the html to fetch the JSON data.
http://www.w3schools.com/ajax/

Resources