Handlebars
Handlebars is a great piece of software which allows us to keep the frontend of our web application separated by the underlying logic. In fact, Handlebars is a logicless templating engine which compiles our templates on the fly and serves the resulting web page fullfilled with our data. And it’s terribly easy to learn it and to integrate inan existing project! If you don’t know Handlebars or if you want to know it better, please refers to the official documentation page.
Compile or precompile, this is the question…
Actually, is not a so difficult question to answer to: precompile for sure! Precompiling your templates has 2 significant advatanges for us:
- we can serve our web pages faster because one step of templating process has already been done and templates are ready to be used in the website
- we can use handlebars.runtime.js instead of handlebars.js: a reduced version of Handlebars with a smaller footprint, so faster to load
So we can for sure prefer to precompile our templates, isn’t it? Okay, just put all your templates in a folder we can call (I know it’s not original) templates. Our directory tree will be something like this:
application root
– css – js – templates – template1.hbs – template1.hbs – template1.hbs – index.html |
Now open a command prompt (or a terminal window) and navigate to the application root then type:
handlebars templates/> js/templates.js
This command will compile all the files it’ll find within the directory templates and it will output the result in the specified file (in this example, in the file templates.js hold in the js directory.
You have now just to add the following line within the head tags of your html pages to display your templates:
<script type="text/javascript" src="js/handlebars.runtime.min.js"></script> <script type="text/javascript" src="js/templates.js"></script>
Fantastic!
But, if you’re using partials, this is not enough. Let me remember here what are partials in Handlebars.
Partials templates
A wonderful feature of Handlebars is that you can use a template in another template: this kind of “sub-template” is called partial. But let me explain why this feature can be useful.
To make a long story short, I was developing a small mobile hybrid application to manage my customers and I wanted to have a page to add a new customer and another page to edit an existing customer. This edit page had to:
- show data for the selected client in a formatted list
- allow to hide the list and show a form to edit some data when a button is clicked
So I had created a template for the Add page with my form and another template for the Edit page with the customer data list. But in this second page I wanted to have the form also and I wished to use the same templñate I had already written, avoiding duplicated code. Handlebars allows to get this using partials. Let’s show an example. Imagine this is the template for the edit page:
edit_page.hbs
<h2>Customer {{customer_name}}</h2> <ul> <li>{{address}}</li> <li>{{zip_code}}</li> <li>{{city}}</li> <li>{{state}}</li> <li>{{country}}</li> </ul> <button id="edit_customer">Edit</button>
And suppose you ahve your form in following template:
customer_form.hbs
<form> <label for="customer_name">Customer name</label> <input type="text" name="customer_name" id="customer_name" value="{{customer_name}}" /> <label for="address">Address</label> <input type="text" name="address" id="address" value="{{address}}" /> <label for="zip_code">Zip_code</label> <input type="text" name="zip_code" id="zip_code" value="{{zip_code}}" /> <label for="state">State</label> <input type="text" name="state" id="state" value="{{state}}" /> <label for="country">Country</label> <input type="text" name="country" id="country" value="{{country}}" /> </form>
Well, with Handlebars, we can insert in this template another template just doing this:
<h2>Customer {{customer_name}}</h2> <ul> <li>{{address}}</li> <li>{{zip_code}}</li> <li>{{city}}</li> <li>{{state}}</li> <li>{{country}}</li> </ul> <button id="edit_customer">Edit</button> <div class="edit_form"> {{> customer_form }} </div>
The problem
However, as I said above, this is not enough. With this code I can for sure write something like this in my main javascript:
var html = Handlebars.templates.customer_form(); $('#add_new_customer').append(html);
and I’ll get my Add_customer page with the form: since I didn’t pass any data, the form will be empty, as expected since I want to add a new customer. But if I try to load my edit_customer page the form will be missing.
The solution
To get it displayed I have to map partials objects to templates object before and then it’ll works.
So go to your javascript main script and add this immediately after the jQuery main function (or just be sure to put your code at the bottom of your html page as the best practices teach:
$(document).ready(function(){ Handlebars.partials = Handlebars.templates; //the rest of the code });
Now you can load your customer data wrapping them in a variable like customer_data and then call you edit_customer page using your precompiled teplates and partials:
var html = Handlebars.templates.customers(data); $('#target-div).append(html);
Just for a more complete example look at the following code, whcih is getting data from a database hosted on a server through an Ajax call and then use Handlebars termplate to display them in a div with id customer list:
$.ajax(function(){ url: 'get_customers.php', type: 'post', success: function(customers){ for (var i = 0; i < customers.length; i++){ var data = customers[i]; var html = Handlebars.templates.customers(data); $('#customer_list).append(html); } }, error: function(jqXHR, textStatus, errorThrown) { console.log(textStatus, errorThrown); } });
To solve my problem with my small application I googled a lot and I found several useful resources. The most useful have been:
http://berzniz.com/post/24743062344/handling-handlebarsjs-like-a-pro
https://www.raymondcamden.com/2015/03/14/quick-handlebars-tip-concerning-precompilation
And decisive has been he Nathan’s solution to this thread:
I just wanted to put it all together trying to avoid other devs have to search the Internet to find the trick 🙂 : hope this help.
This is actually really helpful, cheers.
Thank you, Pleb. Glad it helped you 🙂