A Scripts Section for your Handlebars Layout Template
August 25, 2016I usually prefer ASP.NET MVC for writing web application applications but despite .NET Core and its cross-platform efforts, frameworks like Node.js are often the better and simpler alternative. For application running on a Raspberry Pi I usually use the Node.js based web framework express. It has good documentation, is relatively straight forward to use and offers nice features like templating and layout pages.
About Templating
I like my HTML to be HTML … just sayin’
One thing that I hate about it though, that it relies on Jade (or Pug as it’s called lately) as its default templating language. Your experience may be different, but I simply like my HTML to be written as HTML and not be replaced by yet another language that has its own issues and peculiarities. But I get it: “to each their own” … so chose what makes you happy. For me, that’s another templating language called handlebars.
Handlebars
Handlebar templates are just regular HTML, with embedded expressions that are enclosed in curly braces (which look like moustaches aka handlebars, hence the name).
1 2 3 4 5 6 | <div class="entry"> <h1>{{title}}</h1> <div class="body"> {{body}} </div> </div> |
The Challenge
One thing that it missing from express’s solution is a built-in mechanism for declaring multiple sections in a layout template. Usually, you have a layout file doing all the boilerplate html and detail pages adding their specific content into a container div inside the body.
Quite often, it is helpful though to have at least a second content placeholder where page specific scripts can be put. These are JavaScript files that do not need to go into the layout page, since they are only required on specific pages or execute code that must not run on every page. And since it’s good practice to have your scripts as the last content before closing the body tag, having a dedicated placeholder section would be nice.
The Solution
Luckily, with just a few lines of code and a handlebars concept called helper functions, this functionality can be added.
First, the app.js file has to be modified like this. The helpers property is the relevant part.
var hbs = exphbs.create({ defaultLayout: "main", extname: ".hbs", helpers: { section: function(name, options) { if (!this._sections) this._sections = {}; this._sections[name] = options.fn(this); return null; } } }); app.engine('hbs', hbs.engine); app.set('view engine', '.hbs');
Next, you can define in your layout template file (main.hbs in my case), where you want your script section to go.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <div class="container"> {{{body}}} </div> <script src="/bower_components/jquery/dist/jquery.min.js"></script> {{{_sections.script}}} </body> </html>
Finally, insert the page-specific script where you need it.
<p>Custom Script Section</p> {{#section 'script'}} <script type="application/javascript"> $(function() { alert("Hello World!"); }); </script> {{/section}}
Done!