An Introduction to Handlebars

An Introduction to Handlebars

Tutorial Details
    • Language: HTML / JavaScript
    • Library: Handlebars.js
    • Version: 1.0 beta 6
    • Estimated Completion Time: 45 Minutes

If your site’s data regularly changes, then you might want to take a look at Handlebars. Handlebars is a template processor that dynamically generates your HTML page, saving you time from performing manual updates. In this tutorial, I’ll introduce you to Handlebars, and teach you how to create a basic template for your site.


Site Template

There are two primary reasons why you’d want to make a template for your site. First of all, building a template encourages you to separate the logic-based code from the actual view, helping you adhere to a View/Controller pattern. Secondly, templates keep your code clean and maintainable, which, in turn, makes the process of updating your site a breeze. You don’t create a site with Handlebars. Instead, you create guidelines and structures that dictate how the site should look without focusing on a page’s data. Let’s cover some of the basics.


The Basics

Handlebars generates your HTML by taking a JSON structure and running it through a template. These templates are written mostly in regular HTML, and are peppered with placeholders that allow you to inject data, as needed. For example, the following template greets the user when they log in:

<h1>Welcome back, {{name}}</h1>

The {{name}} attribute is where the user’s name will be injected into the page. This placeholder corresponds with a property in the data’s JSON structure. This is the most basic example possible, but you will soon see that everything else basically boils down to this simple concept. Let’s move on to handling arrays.

Arrays

Handlebars comes with some built-in helpers to assist you in working with more complex data. One of these helpers is the each helper. This helper iterates through an array and allows you to create dynamic HTML, per array element. For example, the following template displays an array’s data that contains a list of the local concerts playing in my area:

<table>
	<tr>
		<th>Local Concerts</th>
	</tr>
	{{#each Concerts}}
		<tr>
			<td>{{this}}</td>
		</tr>
	{{/each}}
</table>

As you can see, this code is much cleaner than conventional code, such as using a loop in PHP or JavaScript to append HTML to a variable. Handlebars is not intrusive, and this is what makes Handlebars so accessible. You may also notice that we use the attribute name, this, to retrieve the current array element in the each loop.

This example is good for an array of simple values, but how do you handle more complex data? Well, you essentially do the same thing. For example, we’re going to write a template for the following data:

[	
	{
		Name : "Band",
		Date : "Aug 14th, 2012",
		Albums : [
			{
				Name : "Generic Name"
			},
			{
				Name : "Something Else!!"
			}
		]
	},
	{
		Name : "Other Guys",
		Date : "Aug 22nd, 2012"
		Albums : [
			{
				Name : "Album One"
			}
		]
	}
]

We can easily display this information using the following template:

<table>
	<tr>
		<th>Band Name</th>
		<th>Date</th>
		<th>Album Name</th>
	</tr>
	{{#each Bands}}
		<tr>
			<td>{{Name}}</td>
			<td>{{Date}}</td>
			<td>{{Albums.0.Name}}</td>
		</tr>
	{{/each}}
</table>

You can store your template in a <script /> element and load it with JavaScript.

In Handlebars, you can even access nested properties, like in the example above (Albums.0.Name), and of course, you could have used another each loop to iterate over a band’s albums. It’s worth noting that besides the dot notation to access nested properties, you can also use “../” to access a parent’s properties.

What if there aren’t any bands playing? You certainly don’t want an empty table, and Handlebars thankfully provides if, else and unless helpers. The if and else statements work like most programming languages: if the object you pass is false or falsey, then the else statement executes. Otherwise, the if statement executes. The unless statement is pretty interesting; it’s essentially an inverted if statement. If the expression is true, the unless block will NOT run. So let’s incorporate these helpers into our code:

{{#if Bands}}
	<table>
		<tr>
			<th>Band Name</th>
			<th>Date</th>
			<th>Album Name</th>
		</tr>
		{{#each Bands}}
			<tr>
				<td>{{Name}}</td>
				<td>{{Date}}</td>
				<td>{{Albums.0.Name}}</td>
			</tr>
		{{/each}}
	</table>
{{else}}
	<h3>There are no concerts coming up.</h3>
{{/if}}

Custom Helpers

Handlebars gives you the ability to create your own custom helper. Simply register your function into Handlebars, and any template you compile afterwards can access your helper. There are two kinds of helpers that you can make:

  • Function helpers are basically regular functions that, once registered, can be called anywhere in your template. Handlebars writes the function’s return value into the template.
  • Block helpers are similar in nature to the if, each, etc. helpers. They allow you to change the context of what’s inside.

Let me show you a quick example of each. First, I’ll register a function helper with the following code:

Handlebars.registerHelper("Max", function(A, B){
	return (A > B) ? A : B;
});

The first argument passed to registerHelper() is the name of my customer helper; I’ll use this name in the template. The second argument is the function associated with this helper.

Using this helper in a template is extremely simple:

{{Max 12 45}}

This template uses the Max helper, and passes the values 12 and 45 to the associated function. Handlebars function helpers support multiple parameters. You can directly insert numbers into the template itself, or you can use attributes from a JSON structure.

Now let’s look at a custom block helper. Block helpers allow you to set the context before running the code contained within the block. For example, consider the following object:

{
	Name: "Parent",
	Sub: {
		Name: "Child"
	}
}

In order to display both names, you can write a block helper that runs the template once with the parent’s context, and once with the child’s context. Here is the helper:

Handlebars.registerHelper("BothNames", function(context, options){
	return options.fn(context) + options.fn(context.Sub);
});

And the template looks like this:

{{#BothNames this}}
	<h2>{{Name}}</h2>
{{/BothName}}

The hash tag before the helper’s name tells Handlebars that this is a block helper, and you close the block not unlike you would an HTML tag. The options.fn function runs the section of template inside the block with whatever context you give it.

Now that we have the basics down, let’s start creating a full demo.


Building a Site Template

You don’t create a site with Handlebars.

The template we will build is for a recipe site. This will give you a good understanding of Handlebars, as it encompasses getting data from an API and passing it through a template.

Setting up a Handlebars project

We must first load our template script, but in order to do that, we need to create a new HTML file and include our Handlebars library:

<html>
	<head>
		<title>Handlebars Demo</title>
		<script type="text/javascript" src="Handlebars.js"></script>
	</head>
	<body>
		<script id="Handlebars-Template" type="text/x-handlebars-template">
		</script>
	</body>
</html>

For convenience, you can store your template in a <script /> element and load it with JavaScript. This is much cleaner than storing it directly in a JavaScript variable.

Now let’s discuss how this app is going to work. First, the app connects to an API (I’m using Yummly) to pull in information on some recipes. Next, we pass this info to Handlebars and run it through the template. Finally, we replace the body section with the newly generated HTML. It’s a fairly straight forward process; so, let’s start by adding a second script block right before the closing body tag, and instantiate an Ajax variable:

<script>

var Ajax = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");

Ajax.onreadystatechange = function(){
	if (Ajax.readyState == 4 && Ajax.status == 200)
	{
		//Parse the JSON data
		var RecipeData = JSON.parse(Ajax.responseText);
		
		//Get the Template from above
		var Source = document.getElementById("Handlebars-Template").textContent;
		
		//Compile the actual Template file
		var Template = Handlebars.compile(Source);
		
		//Generate some HTML code from the compiled Template
		var HTML = Template({ Recipes : RecipeData });
		
		//Replace the body section with the new code.
		document.body.innerHTML = HTML;
	}
}

Ajax.open("GET","Recipe.php", true);
Ajax.send();

</script>

If your site’s data regularly changes, then you might want to take a look at Handlebars.

This is the complete code for compiling and generating HTML code from a template. You can technically pass the JSON data from the API directly into Handlebars, but you run into cross origin issues. Instead of performing some sort of hack or using PHP to “echo” the data into a JavaScript variable, I decided to put all of that into a separate file: Recipe.php. So before we start building the template, let’s go take a look at that PHP file.

Getting The Data

The Yummly API is pretty simple. There is no elaborate authentication system; you just have to sign up, get some credentials, and insert them into the URL. You can directly echo the data if you want to, but I want a bit more detailed info on each recipe. Therefore, I will process the data from the first API call and make a second request for every recipe. Here is the complete PHP script:

<?php
	//Empty Array to hold all the recipes
	$Json = [];
	
	$UserID = //Your ID Here;
	
	$UserKey = //Your Yummly key;
	
	//This searches Yummly for cake recipes
	$Recipes = file_get_contents("http://api.yummly.com/v1/api/recipes?_app_id=" . $UserID . "&_app_key=" . $UserKey . "&maxResult=2&requirePictures=true&q=Cake");
	
	//Decode the JSON into a php object
	$Recipes = json_decode($Recipes)->matches;
	
	
	//Cycle Through The Recipes and Get full recipe for each
	foreach($Recipes as $Recipe)
	{
		$ID = $Recipe->id; 
		$R = json_decode(file_get_contents("http://api.yummly.com/v1/api/recipe/" . $ID . "?_app_id=" . $UserID . "&_app_key=" . $UserKey . "&images=large"));
		
		
		//This is the data we are going to pass to our Template
		array_push($Json, array(
			Name => $R->name,
			Ingredients => $R->ingredientLines,
			Image => $R->images[0]->hostedLargeUrl,
			Yield => $R->yield,
			Flavors => $R->flavors,
			Source => array(
				Name => $R->source->sourceDisplayName,
				Url => $R->source->sourceRecipeUrl
			)
		));
	}
	
	//Print out the final JSON object
	echo json_encode($Json);
?>

By building your site with a Handlebars template, you can produce a full site’s worth of code in only a few lines. Here is the entire template:

<script id="Handlebars-Template" type="text/x-handlebars-template">
	<div id="Content">
	  <h1>&Xi;RecipeCards 
	  	<span id='BOS'>Recipe search powered by 
	  		<a id='Logo' href='http://www.yummly.com/recipes'>
	  			<img src='http://static.yummly.com/api-logo.png'/>
	  		</a>
	  	</span>
	  </h1>
	  {{#each Recipes}}
	  	<div class='Box'>
		  	<img class='Thumb' src="{{{Image}}}" alt="{{Name}}">
		  	<h3>{{Name}} <a id='Logo' href="{{Source.Url}}"> - {{Source.Name}}</a></h3>
		  	<h5>{{getFlavor Flavors}}</h5>
		  	<h5>{{Yield}}</h5>
		  	<p>Ingredients:</p>
		  	<ul>
		  		{{#each Ingredients}}
		  			<li>{{this}}</li>
		  		{{/each}}
		  	</ul>
	  	</div>
	  {{/each}}
	</div>
</script>

Let’s run through this code. The first seven lines are just the logo at the top of the page. Then for each recipe, we create a recipe ‘card’ with a picture, name, and ingredients.

The Yummly API returns a list of flavor data (i.e. how sweet, sour, spicy, etc..) for each item. I wrote a function helper, called getFlavor that takes this info and returns the most dominant flavor in the dish. In order for this template to work, we need to load in the getFlavor helper into Handlebars before parsing the template. So at the beginning of the second script section, add the following code before the Ajax code:

Handlebars.registerHelper("getFlavor", function(FlavorsArr){
	var H = 0;
	var Name = '';
	for(var F in FlavorsArr)
	{
		if(FlavorsArr[F] > H)
		{
			H = FlavorsArr[F];
			Name = F;
		}
	}
	return "This Dish has a " + Name + " Flavor";
});

Now, whenever Handlebars sees getFlavor, it calls the associated function and retrieves the flavor information.

At this point, you are free to play around and design the template however you wish, but you will most likely see that this process is slow. This is primarily due to the three API calls before Handlebars loads the page. Obviously, this is not ideal, but precompiling your template can help.


Precompiling

You have two different options, when it comes to Handlebars. The first is to just precompile the actual template. This reduces the loading time, and you won’t have to include the Handlebars compiler with your page.

This also results in a smaller file size, but this doesn’t really help in our scenario.

Our problem is the communication between the browser and the API. If you did want to precompile your template, you can download the Node.js package through npm with the following command:

npm install handlebars -g

You may need to do this as root (i.e. add ‘sudo’ before the command). Once installed, you can create a file for your template and compile it like so:

handlebars demo.handlebars -f demo.js

You should give your template file a .handlebars extension. This is not mandatory, but if you name it something like demo.html, then the template’s name will be “demo.html” as apposed to just “demo”. After naming your template, simply include the output file along with the run-time version of Handlebars (you can use the regular version, but it’s larger) and type the following:

var template = Handlebars.templates['demo'];
var html = template({ Your Json Data Here });

The unless statement is…essentially an inverted if statement.

But, as I mentioned before, this doesn’t really help us in this scenario. What then can we do? Well, we can precompile and output the entire file. This makes it so that we can run the template with data and save the final HTML output – caching, in other words. This drastically speeds up the load time of your application. Unfortunately, client-side JavaScript doesn’t have file IO capabilities. So, the easiest way to accomplish this is to just output the HTML to a text box and manually save it. Be aware of an API’s guidelines on caching. Most APIs have a maximum amount of time that data can be cached for; make sure to find that information before saving static pages.


Conclusion

This has been a quick introduction to Handlebars. Moving forward, you can look into “Partials” – small templates that can be used like functions. As always, feel free to leave a comment or question in the comment section below.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.facebook.com/CraniumDesigns Steve Davis

    I’ve used handlebars on a few projects already. It’s really nice for parsing JSON data into viewable HTML, and pretty easy. I dig it.

  • Abdelwahab

    hey, it looks like the file that i’ve downloaded does not work :(

    • http://gabrielmanricks.com/ Gabriel
      Author

      To get the example working you have to do 2 things; 1) run it in a server (localhost), browsers don’t allow ajax to the file system. and 2) you have to put in your yummly API credentials as that is where it is pulling the info from. Hope this helps

      • http://www.facebook.com/CraniumDesigns Steve Davis

        lies :P i run my handlebars locally. just gotta enable chrome to do it. firefox will run ajax locally though by default.

      • http://gabrielmanricks.com/ Gabriel
        Author

        Smooth ;) I use chrome, wasn’t aware you can enable it. Thanks

  • http://www.facebook.com/Mjiskinng Abdul Mannan Nasir

    A healthy article and worth informative definitely looking forward to explore some new features of handlebars.js. Just for clearing the point, in the Precompiling section with

    command npm install handlebars -g

    we can download handlebars.js not Node.js inst that true?

    • http://gabrielmanricks.com/ Gabriel
      Author

      That is correct you are downloading the handlebars compiler through npm.

  • Cole

    Awesome! You should keep these coming and make it into a series!

  • Parker Ituk

    I’m wondering what are the pros for using handlebars, instead of a framework like Backbone?

    • Parker Ituk

      ignore that question, because I understand handlebars is a templating framework, just like underscore.

      • http://twitter.com/michaelsharman Michael Sharman

        Underscore is a _whole_ lot more than a template engine, from the underscore site:

        “Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects.”

  • hasan

    Super blog and thanks to share..

  • Anand Kumar

    How it is better than regular code in terms of loop and html ?

    • http://gabrielmanricks.com/ Gabriel
      Author

      I am assuming that you are talking about creating html with a loop in javascript or php. Those are both viable options the only difference is that here you have a framework to work off of and there you would have to do everything from scratch. The final HTML would be the same though

    • http://www.facebook.com/CraniumDesigns Steve Davis

      because it’s so much easier and faster than looping through things manually with javascript. much more maintainable.

  • Mihkel

    Is it possible to get the index number of each iteration in the loop? I’ve come to conclusion that it is only possible when you create your own looping mechanism and this so far has been the biggest setback for me when using handlebars.

    • http://gabrielmanricks.com/ Gabriel
      Author

      Ya it doesn’t seem to be possible without creating your own helper.

  • dailysleaze

    Don’t you get a flash of no content as the javascript inserts the values?

    • http://gabrielmanricks.com/ Gabriel
      Author

      where?

      • garbage190

        When you say “For convenience, you can store your template in a element and load it with JavaScript. This is much cleaner than storing it directly in a JavaScript variable.”
        I can only see a blank square and I can’t see the example.

      • http://gabrielmanricks.com/ Gabriel
        Author

        I put a blank script there as a placeholder. it get’s filled in by the second code block in the section “Getting The Data”.

      • garbage190

        You are right! Sorry, I was thinking about an external javascript file. It’s because I have seen some *.handlebars files somewhere but I can’t figure how to use them.

      • http://gabrielmanricks.com/ Gabriel
        Author

        If it helps you can compile them with the npm package “handlebars”

      • garbage190

        Thanks. I’ll try it.

  • http://twitter.com/ted_drake ted_drake

    Don’t be lazy, make your examples accessible. You’ve got table headers lacking scope=”col” and images lacking alt attributes. Your code samples will be copied by less experienced web developers and we have enough inaccessible content already.

    • http://gabrielmanricks.com/ Gabriel
      Author

      I have also been receiving requests to include demos so people can try it before they download the source. I will try to do both of these things in the future. Thank you.

  • Joel Israel

    I have a VERY important question in Handlebars !
    how to make a for i=0, i<n, i+1 type of block ?

    Because sometimes, you're given a full array and you might chose to only show the first n element … How do you do that ?

    • http://gabrielmanricks.com/ Gabriel
      Author

      Code seems to get formatted weirdly in the comments but what you are looking for is called “block helpers” they have a good tutorial for this on the handlebars site under “simple iterators”. Hope that helps.

  • Preexo

    wow, really great work…

    you should check out angularjs ;)

  • Tony Brown

    Handlebars is my favorite one to use, nice write up!

  • http://www.facebook.com/dragan.valjak Dragan Valjak

    Already use them on the website http://www.zagrebacki-kalendar.com.hr

  • http://www.facebook.com/abualkarmi Mohammad Naeem Karmi

    Interesting topic, thnx

  • JumpedStraightIn

    I don’t normally leave comments on these things,but there’s a couple of issues I wanted to raise with this post. Whilst I am new to handlebars, I found this a great introduction to the notion of javascript templating and I honestly appreciate the author writing it.

    As such I downloaded the demo to get a feel for what I could do with it and started playing around. One of the 1st things I did was edit the recipe.php file to not use an api but some stub data. I added a button and a 2nd php file to act as a file to server results from a 2nd ajax request (so I could simulate calling an api with page parameters for instance). The issues I initially ran in to were that my button was disappearing, this was caused by the fact that in the code, you were replacing the contents of document.body so my button was removed when the data loaded – quite obvious what’s going on when you look at it but not something I would have expected to see being done. Also (and this might just be a personal thing) I don’t see why most people would use a template to replace the whole document body(but again I appreciate it is an example).

    Once I realised what was going on, I created a new div to hold the output from the template with id=output. I then started testing out my ajax request to append extra data. Using firebug I saw that my ajax requests were working fine and the correct data was returned. However, looking at my page the initial items were gone and my new ones took their place! They weren’t appended even though my code was correct. I thought this might be becase my template sat within the area I was trying to append to. The issue actually was the absolute styling applied meant all the items were there,they were just sitting on top of each other. Again a simple thing once I noticed it as I just had to adjust the styles, but it wasn’t something I was really looking for and spent a while thinking it was something to do with handlebars and that it was an issue with my javascript and use of handlebars.

    I genuinely am grateful for this tutorial as I really see a lot of potential in using handlebars, but I just think there were a few “gotchas” in how some of the code/css was structured. I admit they were actually simple enough to fix once I realised what was happening, and a more thorough investigation using firebug would have revealed this sooner, but I also feel that perhaps some inital forethought that people might tinker with the example to understand it better might have resulted in slightly more usable code and css. As I say, I do appreciate these are small things and you want to make the example look nice, but I also suspect that a lot of people might do what I did, jump in playing with the handlebars part and then think it’s not working due to an error on their part, rather than some simple issues with css etc that I wasn’t expecting to play around with as part of the tut. Apologies if this seems like a rant, it’s not I just wanted to offer some genuine feedback about how I approached this tutorial and made use of the downloads. I also acknowledge that if I’d followed through the tut using my own styles I wouldn’t have seen the same issues so I’ve learnt something about how I should approach these tutorials in future!

    Thanks

    • http://gabrielmanricks.com/ Gabriel
      Author

      Thank you for your feedback. I do tend to focus mostly on the article and the source files are kind of like an after thought. But I can see that it is equally as important to have well designed code that can be modified easily. Thanks again for your time.

  • Abdelwahab Bounasser

    $Json = [];

    // this is not compatible with the php below 5.4

  • http://twitter.com/rerrify Terry Rosen

    Thank you for the article, I know these things take a lot of time and I think this will really help beginners to Handlebars or client-side templating in general.

    My only negative comment is that by adding too much logic into the template (basically anything more than an iterator) you are losing the purpose of templating in the first place which as you state is “to separate the logic-based code from the actual view”. I like to keep templates as raw as possible so I know what goes in is what comes out. I’d rather debug in one place (JS) rather than two (JS & template) especially since the section is basically a hack that has no syntax checking or other useful debugging helpers in most editors/IDEs.

    Oh and Camel-case Javascript makes me want to cry :P

  • Jörg Schöneburg

    thanks for this great tutorial i never use a javascript template engine. now I’ll give it a try

  • http://www.facebook.com/lostnitesh Nitesh Pandey

    Good post. Seems lots more are required apart from RequireJS.. like linux or DOS etc :-)

  • Mayur

    Good 1

  • Danny

    I am very interested in **sharing** templates between PHP and a JS templating engine like handlebars. I’ve ran across such a thing, mustache.php. Since Handlebars is a step up from mustache, is there a similar PHP template-parser you can recommend?

    Thanks all!

  • www.codedcontainer.com

    Is there a way that you can use handlebars with Jquery instead of using PHP. If so, could you put an article on Nettuts?