Handlebars.js missing helper - node.js

I'm using handlebars 2.0.0, hapijs 6.5.1 and specifying the helpersPath like this:
var Handlebars = require('handlebars');
var path = require('path');
require('handlebars-layouts')(Handlebars);
module.exports = function(plugin) {
plugin.views({
engines: {
html: Handlebars
},
path: path.join(__dirname, '../public/pages'),
layoutPath: path.join(__dirname, '../public/pages'),
helpersPath: path.join(__dirname, '../lib/helpers')
});
}
The helpersPath is correct. However, it complains saying that my helper is missing even tho it is there and named correctly.
It would seem to me that the helpers are somehow not being registered even tho it knows where they are. Any ideas?

I was having a similar issue, and I think it was related to the format of my helper file.
I was using the examples from the handlebars.js site, rather than looking at the hapijs site. Basically my helper didn't have the module.exports = function(){ ... } a la http://hapijs.com/tutorials/views#view-helpers
Hope this helps.

Related

Connect assets with handlebars?

The typical way to include the connect assets file is
!= css("main")
That is with .jade though. I am using handlebars and I have no clue how I can add the file?
I am using node-sass as well.
Just guessing, something like this works (see blog post):
var connectAssets = require("connect-assets")();
app.use(connectAssets);
var hbs = require('hbs');
hbs.registerHelper('css', function() {
var css = connectAssets.options.helperContext.css.apply(this, arguments);
return new hbs.SafeString(css);
});

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

Options found in locals object in ejs

I got the following error when running the project from GitHub: "options found in locals object. The option(s) is copied to the option object. This behavior is deprecated and will be removed in EJS 3"
I tried to update the ejs and express modules to the newest versions but the notice persists. I googled, ofc, and the only thread about it is this, but it doesn't help.
Does anyone know more about this?
For reference, here is the whole important code:
app/views/index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<img src="img/logo.jpg" alt="Hack Hands logo">
</body>
</html>
app/controllers/index.server.controller.js
exports.render = function(req, res) {
res.render('index', {
title: 'MEAN MVC'
});
};
app/routes/index.server.route.js
module.exports = function(app) {
var index = require('../controllers/index.server.controller');
app.get('/', index.render);
};
app/config/express.js
var express = require('express');
module.exports = function() {
var app = express();
app.set('views', './app/views');
app.set('view engine', 'ejs');
require('../app/routes/index.server.routes.js')(app);
app.use(express.static('./public'));
return app;
};
server.js
var port = 1337;
var express = require('./config/express');
var app = express();
app.listen(port);
module.exports = app;
console.log('Server running at http://localhost:' + port);
tl;dr: Upgrade to the latest version of EJS. It removes all warnings about options and locals.
whoami
I'm a collaborator (or the collaborator in #micnic's comment above) in EJS v2. I only started maintaining EJS after version 2.0.3 (or something like that) was released, so I don't know a lot about how the API changes took place.
History
EJS v2's renderFile function, used by Express.js, now has the signature
function (path[, options[, locals]], cb)
But for compatibility with and Express.js, which calls all functions as
function (path, locals, cb)
with options mixed into the locals object, EJS automatically picks out the locals with option-y names and treat them as options.
But because the Express.js signature is also the function signature of EJS v1, we also print a warning if any option in locals is copied to options, urging developers to use the new signature with locals and options separated (it was actually me who added the warning).
However, Express.js users do not have a choice in terms of calling convention, so the warning is always present in Express.js.
Some users did complain: #34 #36.
At first, #mde (who is the main maintainer of EJS) pushed a fix, which correctly disables warnings on Express.js, and Express.js only.
But then, the person in #36 still complained, as he was using filename as the name of a local, and when the optiony local is copied to options a warning is printed.
At last, #mde was like "f*** this shit" and removed all the deprecation warnings, including an uncontroversial and legitimate one, and released version 2.2.4 (the legitimate warning was restored by me after the release).
Future
#dougwilson (an Express.js maintainer) said he was interested in a separation of options and locals in Express.js v5, just like in EJS v2. I did volunteer to make that change, but then I got busy so yeah.

Get compiled jade template inside view?

I have a "partial" template that I want to use both client-side and server-side.
Is there some method or filter or something that's very similar to include except that instead of executing the template immediately, it returns a client-compiled function which I could then assign to a JS variable and use throughout my script?
At present, I'm doing this:
exports.list = function(req, res){
res.render('file/list', {
...
fileItemTemplate: jade.compile(fs.readFileSync(path.join(req.app.get('views'),'file','file-item.jade')), {client: true})
});
};
And then in my template I have:
ul#folder-list.thumbnails
each file in files
include file-item
...
script(type='text/javascript')
var fileItemTemplate = !{fileItemTemplate};
And in this way I can render some items to HTML on page-load, and then add some more in later by rendering the partial as data comes in.
This works, but it doesn't feel very DRY because I have to read in the file, and deal with filepaths and stuff in the route, and then essentially redeclare the exact same variable client-side.
Is there a nice way of doing this?
Something like this would be ideal:
script(type='text/javascript')
var fileItemTemplate = !{compile file-item};
A possible solution could be JadeAsset. See also the discussion here.
You can hook assets into Express:
assets.on('complete', function() {
var app = express.createServer();
app.configure(function() {
app.use(assets); // that's all you need to do
});
app.listen(8000);
});
To create your Jade assets:
var assets = new AssetRack([
new rack.JadeAsset({
url: '/templates.js',
dirname: __dirname + '/templates'
})
]);

Connect and Express utils

I'm new in the world of Node.js
According to this topic: What is Node.js' Connect, Express and “middleware”?
I learned that Connect was part of Express
I dug a little in the code, and I found two very interesting files :
./myProject/node_modules/express/lib/utils.js
and better :
./myProject/node_modules/express/node_modules/connect/lib/utils.js
These two files are full of useful functions and I was wondering how to invoke them correctly.
As far, in the ./myProject/app.js, that's what I do:
var express = require('express')
, resource = require('express-resource')
, mongoose = require('mongoose')
, expresstUtils =
require('./node_modules/express/lib/utils.js');
, connectUtils =
require('./node_modules/express/node_modules/connect/lib/utils.js');
But I found it a little clumsy, and what about my others files?
e.g., here is one of my routes:
myResources = app.resource(
'myresources',
require('./routes/myresources.js'));
and here is the content of myresources.js:
exports.index = function(req, res)
{
res.render('./myresources.jade', { title: 'My Resources' });
};
exports.show = function(req, res)
{
fonction resourceIsWellFormatted(param)
{
// Here is some code to determine whether the resource requested
// match with the required format or not
// return true if the format is ok
// return false if not
}
if (resourceIsWellFormatted(req.params['myresources']))
{
// render the resource
}
else
{
res.send(400); // HEY! what about the nice Connect.badRequest in its utils.js?
}
};
As you can see in the comment after the res.send(400), I ask myself if it is possible to use the badRequest function which is in the utils.js file of the Connect module.
What about the nice md5 function in the same file?
Do I have to place this hugly call at the start of my myresources.js to use them?:
var connectUtils =
require('../node_modules/express/node_modules/connect/lib/utils.js');
or, is there a more elegant solution (even for the app.js)?
Thank you in advance for your help!
the only more elegant way i came up with is (assuming express is inside your root "node_modules" folder):
require("express/node_modules/connect/lib/utils");
the node installation is on windows, node version 0.8.2
and a bit of extra information:
this way you don't need to know where you are in the path and be forced to use relative paths (./ or ../), this can be done on any file nesting level.
i put all my custom modules inside the root "node_modules" folder (i named my folder "custom_modules") and call them this way at any level of nesting:
require("custom_modules/mymodule/something")
If you want to access connect directly, I suggest you install connect as a dependency of your project, along with express. Then you can var utils = require('connect').utils.

Resources