Rendering a view without res.render - node.js

Following the documentation:
https://github.com/ericf/express-handlebars
I have a need to compile a template, but not using the documented method of res.render('myView'), because in my context there is not res.
This is what I have so far:
var express = require('express')
, exphbs = require('express-handlebars');
, hbs = exphbs.create({
extname: '.hbs',
defaultLayout: 'default'
});
app.use(express.static('public'));
app.engine('hbs', hbs.engine);
app.set('view engine', 'hbs');
var tplVars = {
id: 12345,
name: 'John Doe'
}
hbs.handlebars.compile( .. path to pdf.hbs ... )(vars);
Now, obviously I need to register the template. What is missing here?
My file structure in /views:
views/
layouts/
default.hbs
partials/
css.hbs
pdf.hbs

Copy paste from the comment above.
I don't think you can compile templates with express-handlebars, but you can do so with handlebars.
Details in a previous answer here.

Related

Handlebars registerHelper serverside with Expressjs

I am using expressjs with handlebars as templating engine with following code in Webstorm IDE with express generator.There is no visible handlebars require in the code (I guess express generator has it someplace else which is not visible)
var app = express();
.
.
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
How do i use registerHelper on serverside in this situation ?
My other renderings and partials are working.So handlebars is doing its work.Its just that registerHelper seems to be cause of worry.
I have given a thumbs up to #Mukesh Sharma as he very nearly had the syntax that worked for me and really led me to it.
He is doing a bit more to make it work for the front end I believe. All I needed was the following
// index.js
//in the declarations
const exphbs = require('express-handlebars');
//when configuring the app view engine
app.engine('.hbs', exphbs({
extname: '.hbs',
helpers: require('./config/handlebars-helpers') //only need this
}));
app.set('view engine', '.hbs');
Then I have a simple file I include from where I have helper stuff .
// config/handlebars-helpers.js
module.exports = {
ifeq: function(a, b, options){
if (a === b) {
return options.fn(this);
}
return options.inverse(this);
},
bar: function(){
return "BAR!";
}
}
No need to pass or import handlebars-express - including the simple object of helper functions as part of the exhbs options hash under helpers lets express hbs do all of the registering by it's own approach.
(Bonus ifeq is a tiny helper that compares two arguments and will show the block if true .. useful for something like:
class = "{{#ifeq thisUrl '/about'}}active{{/ifeq}}" .. to set a nav pill class as 'active' )
found it here https://gist.github.com/pheuter/3515945
I think express-generator just sets view engine to hbs only. To configure the hbs engine, you have to use express-handlebars.
e.g.
var app = express(),
exphbs = require("express-handlebars");
app.engine("hbs", exphbs({
defaultLayout: "main",
extname: ".hbs",
helpers: require("./public/js/helpers.js").helpers, // same file that gets used on our client
partialsDir: "views/partials/", // same as default, I just like to be explicit
layoutsDir: "views/layouts/" // same as default, I just like to be explicit
}));
app.set("view engine", "hbs");
And, helpers.js
var register = function(Handlebars) {
var helpers = {
// put all of your helpers inside this object
foo: function(){
return "FOO";
},
bar: function(){
return "BAR";
}
};
if (Handlebars && typeof Handlebars.registerHelper === "function") {
// register helpers
for (var prop in helpers) {
Handlebars.registerHelper(prop, helpers[prop]);
}
} else {
// just return helpers object if we can't register helpers here
return helpers;
}
};
module.exports.register = register;
module.exports.helpers = register(null);
Source: http://www.codyrushing.com/using-handlebars-helpers-on-both-client-and-server/
You can register both your own customer helpers and the ones from 'handlebars-helpers' like this:
const hbshelpers = require('handlebars-helpers');
const multihelpers = hbshelpers(['object', 'string']);
const helpersDM = {
hlp: echo => `Echo: ${echo}.`,
STATIC: `/static`,
};
const hbs = exphbs.create({
layoutsDir: join(__dirname, 'views', 'layouts'),
partialsDir: join(__dirname, 'views', 'partials'),
extname: '.hbs',
defaultLayout: 'base',
helpers: {...multihelpers, ...helpersDM},
});
app.engine('.hbs', hbs.engine);
app.setViewEngine('.hbs');
I was able to add partial and register a helper using hbs.
Seems to be it is the same view engine used within express for templating with handlebars.
According to hbs docs, add the following to the entry point of the application: (index.js or app.js) and before setting the view engine in express.
index.js
const hbs = require('hbs');
const express = require('express');
hbs.registerHelper('number_format', function (option) {
// option :
// will contain the arguments passed
// to the helper from the template
// computation can be done here
return `USD ${option}`;
});
hbs.registerPartial('partial', function (options, ...rest) {
// options :
// will contain the arguments passed
// to the partial from the template
// as a object (key value pair)
// ex:
console.log(option.argOne) // 1
console.log(option.argTwo) // 2
// ----------
// Have a look at the other arguments like context data
console.log(...rest)
// computation can be done here by using argument values
return `partial value: ARG1:: ${option.argOne} & ARG2:: ${option.argTwo}`;
});
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
Partial in a hbs template file
<h1>
{{>partial argOne=1 argTwo=2 }}
</h2>
above will generate the following,
<h1>partial value: ARG1:: 1 & ARG2:: 2<h1>
Helper in a hbs template file
<h1>{{number_format 100 }}</h1>
above will generate the following,
<h1>USD 100</h1>
learn more about handlebars partials using their docs on partials

How to render Swig templates with Express 4?

I am not able to use Swig templates with Express for Node.
I get the following error :
Error: Failed to lookup view "index" in views directory
The Swig templates are not being compiled into .html files
My code is below :
var express = require('express');
var cons = require('consolidate');
var swig = require('swig');
var app = express();
//Set template engine
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/views')
// Disable Express's and Swig Cache
app.set('view cache', false);
swig.setDefaults({ cache: false });
app.get('/', function(req, res){
res.render('index', {'title': 'Design'});
});
app.listen(3000);
I just had the same issue. In order to use swig templates with the swig extension working you can follow the swig Docs and then replace the two following lines with
app.engine('html', cons.swig);
app.set('view engine', 'html');
with
app.engine('swig',swig.renderFile);
app.set('view engine', 'html');
Should look something like this.
var express = require('express');
var swig = require('swig');
var app = express();
// view engine setup
// This is where all the magic happens!
app.engine('swig', swig.renderFile);
app.set('view engine', 'swig');
app.set('views', path.join(__dirname, 'views'));
app.set('view cache', false);
swig.setDefaults({ cache: false });
Expressjs 4.x docs app.engine
The app.engine takes a extension and a callback. So to all files found with the swig extension have a callback of swig.renderFile. Each file with generated to HTML.
Expressjs 4.x docs app.set
Setting the view engineto swig is setting the default engine extension to use when omitted. Were also saying that all the views can be found in the /blaha/blaha/blah/views directory.
NOTE: All files in the views directory must end int .swig.
So just a friendly reminder make sure when you "include" or reference another template you must put the filename and extension it the path. ex: layout.swig. I hope this gets your project working.
As explained here:
http://mherman.org/blog/2015/08/23/primer-on-swig-templating/#.VhWxVvlVhBc
Simply use .html files instead of .swig files. I don't know where you got the idea of using .swig files. Maybe an older version? I dunno. The current Swig's documentation Basic Usage shows using a .html file as well:
http://paularmstrong.github.io/swig/docs/
If you rename your index.swig to index.html I would expect it to work fine.
Yes, i think it's more semantic to store your templates as .swig files, if you using SWIG as template engine. So, all you need is set 'swig' as engine:
// view engine setup
app.engine('swig', swig.renderFile);
app.set('view engine', 'swig');
app.set('views', path.join(__dirname, 'views'));
Then you can store your views like ./views/layout.swig
for latest version of swig we need to include swig package which needed to installed through package manager or package.json file
var express = require('express');
var swig = require('swig');
var app = express();
// Here we need to set up and engine as per latest version of swig
//for latest version of swig we need to include swig package which //needed to installed through package manager or package.json file
app.engine('swig', swig.renderFile);
app.set('view engine', 'swig');
app.set('views', path.join(__dirname, 'views'));
app.set('view cache', false);
swig.setDefaults({ cache: false });
//Here we are setting cache defaults to false.
`

Parse Cloud Hosting with Express and Handlebars Templates

There is a node package for using handlebars templates in Express.js, express-handlebars, but I'd like to be able to use the same package in a Parse Cloud Hosting project. The only discussion I can find about how to make it work is here, and it's painfully brief: https://parse.com/questions/dynamic-website-handlebars-for-template-engine
The last comment mentions specifying the 'cloud' directory 'to the required command for a lot of dependent modules'. The author does not explain how he did that, and the thread is now closed.
After following the install instructions I have this in my main app.js file:
var express = require('express');
var exphbs = require('express-handlebars');
var parseExpressCookieSession = require('parse-express-cookie-session');
var home = require('cloud/routes/home');
var register = require('cloud/routes/register');
var login = require('cloud/routes/login');
var app = express();
// Configure the app
app.set('views', 'cloud/views');
app.set('view engine', 'hbs');
app.engine('hbs', exphbs({
extname: 'hbs',
defaultLayout: 'layouts/main.hbs'
}));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('ABCDEFG1234567'));
app.use(parseExpressCookieSession({ cookie: { maxAge: 3600000 }}));
app.use(app.router);
// Define all the endpoints
app.get('/', home.index);
app.get('/register', register.new);
app.post('/register', register.create);
app.get('/login', login.new);
app.post('/login', login.create);
app.get('/logout', login.destroy);
app.listen();
My file structure looks like this:
cloud
└──routes
└──views
└──layouts
└──main.hbs
└──home
└──index.hbs
└──register
└──new.hbs
└──login
└──new.hbs
config
node_modules
public
package.json
All route files are a slight variation of this:
exports.index = function(req, res){
res.render('home/index');
};
Running my app results in the following error:
Error: Failed to lookup view "home/index"
With the default 'ejs' templates, the app runs fine. Personally, I'm fine with ejs templates, but it's not up to me. Handlebars are what's required of the project, so that's what I'm out to accomplish. Thanks!

Registering handlebars helpers with node does absolutely nothing

I'm attempting to write my own handlebars helpers and am getting no where. I'm using the npm hbs package (Handlebars.registerHelper didn't work) and registering it in app.js like so:
app.set('view engine', 'hbs');
var hbs = require('hbs');
hbs.registerHelper("log", function(something) {
return console.log(something);
});
hbs.registerHelper('test', function() {
return console.log('test')
});
Yet {{log 'test'}} or {{test}} any where inside my template does absolutely nothing. There's no js errors being produced in the browser or terminal consoles. I know handle bars is working correctly since I have other hb variables displaying correctly. I'm at my wits end here trying to do something very simple otherwise I wouldn't embarrasses my self by asking such a simple question.
Thank you for your time.
Thank you for your input mscdex but your response didn't work. I'll clarify how I got it working here for others new to handlebars. I was using the npm hbs package because I found good helper examples. After looking into it deeper, my previous handlebars package "express-handlebars" had some examples on the npm page that actually worked. I think my main confusion was a result of not knowing where the first variable in the declaration was being defined.
Below is the code in my app.js file that declares which handlebars package to use.
var exphbs = require('express-handlebars');
app.engine('.hbs', exphbs({defaultLayout: 'main', extname: '.hbs'}));
app.set('view engine', 'hbs');
Then in the route for a particular page the helper is defined the same way the title or an array of data would be:
res.render('editSite', {
title: 'Update Existing Site\'s Data', siteVars: siteVars, helpers: {
foo: function () { return console.log('test'); }
}
});
You need to actually return a string from your helpers. console.log() returns undefined. Try this instead:
hbs.registerHelper("log", function(something) {
console.log(something);
return ''+something;
});
hbs.registerHelper('test', function() {
console.log('test');
return 'test';
});
in my view, the simpliest way to do what you want, if this is about global helpers (may not be the best solution, but...), is to create your helpers file :
module.exports = {
customif: (options)=>{
return (options.hash.expected === options.hash.val) ? options.fn(this) : options.inverse(this);
}
}
Then, require it :
const handlebarsHelpers = require('./helpers/handlebars');
And finally, when you link express to handlebars, you can insert helpers in the object :
app.engine('hbs', handlebars({
extname: 'hbs',
defaultLayout: 'layout',
layoutsDir: __dirname + '/views/layouts/',
helpers: handlebarsHelpers
}));
And you can use it inside your layout blabla.hbs:
{{#customif expected='foo' val=field}}
bar
{{/customif}}
Works for me...

Access i18next Translation in Function not in App.js

Im using ExpressJS and i18next.
in app.js
var express = require('express')
, i18n = require('i18next')
, user = require('./routes/user')
...
//internationalization
i18n.init({
lng: 'en-US',
saveMissing: true,
debug: true
});
...
app.use(i18n.handle);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
...
i18n.registerAppHelper(app);
...
app.post('/users/save', user.save);
I can access the translation in jade:
t('app.title')
How can I access the translation in routes.user.js
exports.save = function(req, res){
//t('app.title')
}
t is available in your route handlers as res.locals.t. This should work in Express 3 and 2 as well.
i18next-express-middleware -> the translation function could be accessed through req.i18n.t or just req.t. but obviously it's under res.locals.t too - to be accessible in templates.

Resources