What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
JavaScript Templating with Handlebars
by Ryan Lewis
Handlebars is the most widely used JavaScript templating library, supporting both client-side and server-side applications. In this course, Handlebars is covered from basic concepts all the way to production-ready tactics.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Handlebars: An Introduction
Introduction
Server-side rendering versus client-side rendering. The debate rages on, but both sides agree that templating is essential. My name is Ryan Lewis, and today I'll help you level up your websites with this course JavaScript Templating with Handlebars. Handlebars is one of the most popular JavaScript templating libraries, which empowers you to take dynamic data and render it into human readable markup at lightening speed. We'll be covering all the ins and outs of Handlebars, learning best practices for rendering data on the client side, and even taking a peak at how to use it on the server side with Node. In this module, we'll start out by looking at how websites work and why there's a need for a templating solution. Then we'll look at some of the pros and cons when deciding between rendering on the client or the server. I'll introduce you to a templating technology called Mustache, which Handlebars is extended from, and then get into how Handlebars was started and what makes it different. We'll look at Handlebars' features at a high level to get you pumped for the rest of the course. And finally, we'll install Handlebars with the Bower package manager and end out the module with a Hello world example. Let's get started.
Why Are Templates Needed?
If you're watching this course you've likely constructed a website at one time or another or at least understand what goes into building a website. Websites are designed to communicate information visually to human beings staring at some type of screen. The mechanism of getting a computer to display the information the developer wants in a structured way is a programming technology called Hypertext Markup Language, or HTML. This language has been used on the web and interpreted by applications called web browsers since the early 1990s. Even in the early days of HTML, developers realized that in the act of creating the code to display their desired information there was a lot of redundancy in the markup. Oftentimes, they would use the same markup to display different information, causing them to type or copy and paste the same code over and over again to create a multi-page website. If a change was needed to the look of a website, code would have to be changed in multiple places, making the probability of errors quite high. At some point, developers realized that if they used a template pattern, writing their HTML markup once, and then populating it with different data, the stability of their websites could be greatly increased and redundancy decreased. Using templates made it easier to build websites quickly and make changes. Rendering HTML with templates quickly became an industry standard. And despite template-rendering technologies coming and going, the practice of using templated HTML has only grown.
The Client-side vs. Server-side Debate
One of the great developer flame wars has been around client-side versus server-side rendering of HTML templates. Both sides agree that templating is the correct approach, but where to do it is what's in contention. In the early days of HTML templating, server-side rendering was the only option. But now that browsers are becoming more and more powerful, client-side rendering has quickly become an attractive option. First, just a quick recap on each. Server-side rendering means that the markup that the user sees is dynamically created on the web server and delivered to the browser ready to go. Client-side rendering means that a template and data is delivered to the browser and then rendered and displayed for the user. Here's what server-side rendering proponents say about client-side rendering. Requiring your presentation to be rendered using inconsistent browser specs puts an unneeded strain on low-powered clients, especially mobile devices. Making the user wait while the templates render at the beginning of the app is unacceptable. And there are still some issues with getting client-side rendered apps to be optimized for search engines. The client-side rendering supporters have a similar list of arguments. Rendering on the server side means sending redundant markup to the client, costing bandwidth and increasing page rendering time. The responsiveness and user experience of a client-side rendered application surpasses the slow, wait-for-it-to-load nature of a server-side rendered app. Both sides have completely valid points, and I believe a complete solution uses both. Search engine optimization is a real consideration that rendering completely on the client makes extremely difficult. In addition, an instantly rendered initial page load is a better first impression than a blank page. So the ability to render on the server for those scenarios is a huge boon. On the other hand, rendering on the client is basically a standard for using any client-side framework, and the speediness of click and it's there is practically expected by users today. Client-side rendered applications from large companies such as Google only embed the UX expectations further into users' minds. I recommend an approach that utilizes rendering on both sides, delivering an initial page that is server rendered and any subsequent pages be rendered on the client. Handlebars, the templating library we'll learn today, is fully functional on both sides of the rendering divide, allowing you to decide what's best for your application.
The Mustache Philosophy
The Mustache templating specification was first released around 2009 and was first implemented in Ruby. Over the years, it has been implemented in nearly every popular programming language. The specification itself is only around 1000 words, and that minimalism is part of its success. Handlebars is an implementation of the Mustache spec and carries on much of the philosophy and syntax of vanilla Mustache. Mustache proposes to keep your logic out of your templates. There are no logic sections such as if and else or for loops, only Mustache tags that are replaced by values. This makes Mustache dead simple to understand and usable in an endless variety of situations. Why have logic-less templates, you may ask? It's all about separation of concerns. Mustache and templates in general are used to create the presentation layer of an application. The main concern of templates is how something looks, not processing and branching to choose what to display. Keeping application logic separate from presentation markup is a best practice. Separation of concerns is primarily motivated by the simplification of application development. Having a single place to change your interface makes it much easier to maintain and reuse for other parts of your application, as well as testing.
Birth of Handlebars
Mustache's simplicity is why it's so flexible and powerful. For many use cases it can be implemented quickly and easily. However, in the land of JavaScript, the infrastructure to render a template can be extremely cumbersome. A naïve JavaScript application implementing Mustache might integrate templates so tightly with the code that it would defeat the separation of concerns principle. The logic-less templates would be embedded in JavaScript logic making the templates difficult to maintain. With a good application design these problems could be avoided, but developers would often find that they're having to solve the same problem over and over again with custom code. It was with this intent that the Handlebars templating library was created. Handlebars fully complies with the Mustache specification, but approaches it with an understanding of the JavaScript development life cycle. Handlebars provides simple patterns and infrastructure to easily render data with Mustache templates. It also adds a killer feature with helpers, used to extend the abilities of your Mustache templates, enabling them to be used in any possible situation. With these small additions, Handlebars adds enough functionality to Mustache to make it an essential tool in any developer's toolbelt. Let's look at a quick list of the key things that Handlebars adds to Mustache. Remember, it fully complies with the Mustache specs so anything that Mustache can do Handlebars can do. Here, we'll be looking at just what makes Handlebars special. First, Handlebars gives you a compile function, which enables the pre-compilation of templates. This is an extremely powerful function that you can use in your application to speed up the rendering and performance of your templates. Pre-compilation is also great to use in your build pipeline, which we'll see in the last module of this course. Next is one of Handlebars' most important features, helpers. Helpers enable you to add functionality by registering your own JavaScript functions that run in the context of your templates. Helpers are so important I've devoted an entire module in this course to covering them. Handlebars ships with some built-in helpers such as if, else, an each iterator, and a with block. Another powerful feature added to Handlebars is the nested path structure. In vanilla Mustache, each tag references an object or property. Going deeper into an object such as a child property or even lower requires nesting tags. This can quickly become difficult to read and maintain. Handlebars allows you to describe nested paths in a single tag using the JavaScript dot notation you are already familiar with. It seems almost silly how such a simple addition adds so much to the usefulness of a templating library. There are many smaller features that Handlebars adds and we will explore many of them throughout this course, but these are the three major features that easily sells Handlebars.
What It's All About
Now that we have some history out of the way, let's take a step back and talk about what Handlebars is and what it isn't. This should make clear exactly what Handlebars can be used for. Handlebars is a JavaScript library that is used to take templates, which at the simplest are just strings, and populate them with data. Handlebars can be used with any kind of template, be it HTML, XML, or plain text. Handlebars merely looks for tags, helpers, or any type of special block. Any text outside of those is ignored and rendered unchanged. You can even render a string with no tags with Handlebars and you'll get back the exact same string. Although, I don't know why you'd want to do that. The data that Handlebars takes is a JavaScript object, an array, or even a function. Handlebars will use any tags in the template and attempt to populate them with the matching data that was passed in. Handlebars does not make any decisions on where to put your templates. The Handlebars website gives examples of storing your templates in the DOM and accessing them via jQuery. This is perfectly acceptable for examples, and we will build much of our demo application using that same approach. But it's too tightly coupled for a real application. In the last module of this course, we'll learn how to compile your templates into an easy-to-include file that will make it much easier to scale your application. Handlebars is also platform agnostic. It is typically used in browsers to dynamically render templates and data, but can also be used on the server when rendering HTML to return to a client with a Node application. There are third party developed Handlebars libraries implemented in many programming languages such as Java, C#, Rust, Scala, and many more. These may deviate from the official documentation though so take care when using them. Well, we finished our overview of Handlebars. It's time to pull down the dependency and take it for a spin.
Installing Bower
When using a third-party library from around the web, you have several options for how to add it to your code. One way is to use a CDN provided by the library. Most of the larger libraries such as jQuery or Bootstrap provide these for free. For smaller libraries, you can often find them on CDNJS, a service which puts a variety of libraries on a CDN for free. The downside to this approach is relying on another request for your application. In addition, you can't optimize the loading of that library. You are completely at their mercy. Another method is to download the code from the library's site and store it locally. This allows you to perform optimizations to speed up the download of the content to your site. The downside is that it can be difficult to scale with a larger team. You could store the source code in your own repository, but this is generally considered a bad practice and can make upgrading versions difficult. Package managers have long been the industry-proven solution to this problem. NuGet, Gems, pip, Maven, all the popular languages have widely used package managers that make sharing code simple. Client-side JavaScript has lagged behind in this respect, especially considering it is over 20 years old at this point, lacking a solid package manager for most of its existence. A few years ago, this problem was solved by our good friends at Twitter with the release of a client-side package manager called Bower. Bower is a repository and tool for downloading JavaScript and CSS dependencies. Despite some criticisms, it has become the de facto solution for including dependencies on the web. To install Bower, you will need to have Node.js and npm already installed. I've provided an up-to-date article on my blog that should help you take care of this prerequisite if you don't already have it installed. Just go to the following link, follow the steps, and then come back to this video. We'll need a command line to install Bower since we will use npm to do the installation. If you're on Windows, the default command prompt works fine. On Mac, you can use Terminal. And I shouldn't need to give any advice to you Linux users. It doesn't matter where you're at in your command line since we're installing globally. Execute the command npm install -g bower to install Bower globally and add it to your path. Mac or Linux users will need to prefix that command with sudo and enter their passwords, just like I'm doing here. Once npm has taken its time installing Bower, you'll be returned to a command prompt. Here, let's go ahead and make sure Bower is set up correctly. Execute the command bower --version, which will tell us which version of Bower we're on and confirm that everything is working correctly from our command line. You should have some output like you see here. If not, check the previous output from the install command to see if something went wrong.
Hello Handlebars
Before we get started, just a quick note on the software I'll be using in this course. For my text editor I'll be using Atom. This is a newer editor developed by GitHub, and it's free to download and available on all major platforms. I'll be using the default Mac terminal so just use whichever you're comfortable with. For the browser, I'll be trying out Vivaldi, which is still in technical preview as of this recording. It's a new browser developed by the team that was formerly behind the Opera browser. It's also available on most major platforms. With Bower installed, we're going to write our first Handlebars template and render it. Nothing too fancy just yet since we haven't gone into Handlebars syntax. I won't explain many of the concepts until the next module so just follow along with my steps. Let's start by creating a new project directory. I'll set mine up in my documents folder and call it handlebars-app. You can use this same directory for the demo application we'll develop later or this can just be for the current exercise. In your command line, navigate to the folder you've created. We'll install Handlebars here with Bower using the command bower install handlebars. If you're a npm user, this structure should look very familiar. The Bower command line pattern follows after npm very closely so you can use most of the npm commands in Bower as well. You should see some output that looks similar to what's on my screen. Once you're back to the prompt, Handlebars should have been downloaded into the bower_components folder. You can change directories into bower_components and see that a handlebars folder has been created just like this. Now, bring up your text editor and we'll get started. Create a new file called index.html. We'll save that in the handlebars-app project directory that we created. This file will be the only file we'll need to create for this exercise. It will contain all of our code. We'll start with some boilerplate HTML. Add opening and closing html tags. Then, inside that, add some head tags towards the top. Inside the head tag, we'll go ahead and import our Handlebars JavaScript dependency. Open a script tag and set the source to the path to your Handlebars file in the bower_components folder. Your installation may be the same as mine, but I can't tell you that for sure without looking at your machine. The Handlebars JavaScript file that we want to include is located at bower_components/handlebars/handlebars.min.js on my computer. Verify the path on yours as well. I'll include that as the source attribute in my script tag and then close it out. After our head section, we'll add a body section. The only display element we need is a placeholder for where we will insert our rendered template. Create a div tag and give it an ID of app. That's it for our presentation. Now, we'll write some JavaScript. So, create a script block. The first step of our JavaScript is to compile a template with Handlebars. We'll save the compiled template in a variable called template. So declare that with var. To create this compiled template, we'll call Handlebars.compile and pass in our template as a string. Our template is going to be very simple, and we'll create it as a string literal right here. Start with a div tag, which will wrap our template. We'll add the word Hello, and then we're going to enter our first Handlebars tag. A Handlebars tag starts with two open curly braces. Then, you enter any type of identifier. Here we'll put name. Then close the tag with two closing curly braces. To end our template, we'll close the div tag and close our quotes. It may not look like much right now, but this is a fully functional Handlebars template. Once the compile function has processed it, it will be ready to take data and render it to a finish string. In the next line, let's grab the element we want to insert the rendered template into. Create a variable called appEl. Then, use the document.getElementById function to get the div with ID of app and assign it to this variable. Now that we have our compiled template and the element to insert it into, let's make some magic happen. We want to insert the rendered HTML into the inner HTML property of our appEl variable. To do this, we'll call the template function that was created from Handlebars.compile. We will pass our data into this. So, create an object with the property name and give it the value Handlebars. This name property directly corresponds to the name tag in the template above. And with this, our JavaScript is done. If you need to, go ahead and close the script block. Just to go back through our steps, first, we compiled a template using Handlebars, then, we're storing a reference to the DOM element where we want to insert the rendered template, finally, we do the insertion by calling the compiled template like a function and passing in some data that is used to create rendered HTML. Let's go ahead and try it out in our browser. Just open up the file in your browser of choice. If everything's working then you'll see a Hello Handlebars in the top left corner just like this. The cool thing about this is that this simple action, taking data and creating HTML, is the basis for much bigger things. Rendering tags is just a small piece of Handlebars' functionality, and you'll be impressed with some of the other things it can do.
Conclusion
That's it for module 1. We started the module discussing the problems that templating solves, improving modularity and reducing redundancy. Then I discussed some pros and cons of client-side and server-side templating. In many cases, using both is actually the best option. Then I revealed the Mustache philosophy and described the shortcomings, which Handlebars overcomes. I gave you the low-down on Handlebars, setting you up to be successful once we start learning the code. We installed Bower, our client-side package manager. And finally, we pulled down the Handlebars dependency and wrote a little Hello world application with templates. In the next module, we're going to start learning Handlebars syntax. Did you think it was going to be as simple as tags? Oh no. We'll learn about paths, blocks, lists, partials, and oh so much more. We'll also start working on our demo application, which is going to have super cute dogs because I like them. And I wanted to say dog about 100 times in the next hour and a half. So, see you in the next module.
Building Blocks of Handlebars
Introduction
Hello, and welcome back to JavaScript Templating with Handlebars. I'm Ryan Lewis, and this module's going to be filled with syntax lessons. I hope to change the way you think about building on the web. We'll be converting a static web application into a templated one, which should prepare you for migrating your own or starting from scratch. We'll start with a walk through of the demo application and the expected functionality. This should get you stoked for some of the things that templating makes easy. Then we'll look at basic Handlebars expressions and start converting the demo app. Next, we'll look at lists in Handlebars and then the if/else block structure. We'll take a look at how to simplify your template structure by using partials. And finally, I'll share a few tricks with Handlebars that you can keep up your developer's sleeve. Well let's jump into it.
Demo Application Walkthrough
This is dog or not?, the internationally popular game/dating app. Users look at a picture and indicate whether it shows a dog or not a dog. The user can click on the DOG or NOT buttons and when they do the selected button highlights and the score in the top left updates to their current number of correct, incorrect, or incomplete dogs. Feedback on their choice is show in the dog card, and users can select the opposite option if they get it wrong. I know, this is a really hard game, right? Just go with it. Pagination is dynamic and fully functional, letting users easily move between pages. Query parameters are used for application state, as you can see the page attribute updating here. There are filters as well with the DOGS, NOT DOGS, and MAYBE DOGS menu options. These also use query parameters and support pagination. The last feature is language switching since we are really aiming to tap into the canine dating market with our app. This DOG? button will change the language to canis lupus familiaris, or dog. I'm not actually fluent in dog so I won't attempt to read out the labels, but you can see that all the functional labels in the site have changed language. That's pretty much all of the features for the app we'll be building. We'll be starting with a husk of this site with all the CSS, nearly all the HTML, and some of the JavaScript prepared for you. We will take this starter code and turn it into a functioning app by primarily using Handlebars and some JavaScript sugar. You can get the starter code through my site, which is linked below. Pull down the code and put it in a directory to work from. You can use the same directory we made in module 1, handlebars-app, or make a new one. In the next clip, we'll get started with some coding so go ahead and get the starter code prepared.
Handlebars, jQuery, MDL
Besides Handlebars, we'll be using a few other dependencies to make our apps sing. We'll use Bower to pull these down just like we did with Handlebars. Now, you may have started a new folder with the starter code so we'll want to download Handlebars again as well. And since we're going all in with this app and trying to use best practices, let's use Bower the best way. In your command line, navigate to your app directory. What we want to do is use a bower.json file to help manage our dependencies. What this file does is keep some metadata about your app, as well as the dependencies that it uses and the versions. This makes it easy to keep dependencies aligned between team members by sharing this file. If you're familiar with npm, this is basically the Bower equivalent of a package.json file. Execute the command bower init to have Bower generate the bower.json file for you. It will run you through some questions about your app. Just answer whatever you want here. We won't actually be using this data anywhere. Once it's complete, your bower.json file has been created and you're ready to start installing dependencies. There are three dependencies we need, Handlebars for our templating, jQuery for DOM manipulation and utility methods, and Material Design Lite, a CSS framework from Google that will provide a lot of the styles for our site. With Bower, you can chain together installations so let's do that. And one more thing, we will be using Handlebars version 3.0.3 in this course. So, we'll specify the Handlebars version when installing. In your command line, type bower install --save jquery handlebars#v3.0.3 material-design-lite. That's l-i-t-e. This will install all three of our dependencies in one go and save them all to our bower.json file. One key thing to know about Bower, it uses the Git protocol to access repositories on GitHub. If you're at work or behind a firewall, there is a possibility that the Git protocol may be blocked. If you encounter any issues when trying to install something from Bower this may be the cause. To resolve this, configure your Git installation to use the HTTPS protocol instead of Git. Execute this command into your command line to change this and then retry the bower install command. We've got all three of our external dependencies lying in wait in our bower_components folder. In the next clip, we'll start hacking on our demo application.
Handlebars Expressions
The basic structure in Handlebars is the expression. Every Handlebars expression is wrapped in double curly braces. We could call these tags as a general term, but Handlebars will actually be processing these. So, I'll use the term expression to be more specific. Looking at a Handlebars template, you can imagine that the Handlebars expressions are all that the Handlebars engine sees. Everything outside of those expressions are returned by the Handlebars rendering engine unmodified. That means you can put Handlebars expressions inside quotes, parentheses, in the middle of words, surrounded by madness, basically anywhere. Even though we'll be using Handlebars to render HTML pages, you can really use Handlebars with any string for any purpose. Inside an expression are space delimited parameters. The first of those parameters is what Handlebars will use to search for a match to render. There are some more advanced expressions, but we'll start looking at expressions with a single parameter just like this one. Each template that is rendered has a context, which must be supplied by the caller. If I passed in this object as my context to render, Handlebars would use that to render this specific expression into the string Dogs are the best! We could change the context that would be passed in and the rendered string would change as well just like this. This is the most basic operation in Handlebars. It might sound exactly like what Mustache proposes in the spec and it totally is, so let's look at how Handlebars works differently. All the Handlebars dependency code is stored in a global Handlebars object. To compile a template and prepare it for rendering, you would use the Handlebars.compile method. The template would be passed in as the first argument with an optional options object as the second argument. The compile function returns a new function, which is typically saved for later use. This return function holds the template that you originally passed in and should be called with some data that you want to render with the function. You can call the function as many times as you would like, as it doesn't store any data passed into it once it's compiled. In this way, you can effectively cash your compiled templates, saving yourself a little time and memory when rendering them multiple times. The return function from compile returns the rendered template as a string, which you can then insert into your DOM or use in whatever other method you need it. Here's a full example taking a simpleton plate, compiling it, and rendering it with data. This is what I like to call the Handlebars dance and you'll do it plenty when using Handlebars. Just to reiterate the steps to use Handlebars with a website, you'll start by getting your template, then you'll compile your template, render your template with data, and finally insert the rendered template into the DOM. Before we start doing some editing, let's look at another simple thing that Handlebars adds to Mustache. I mentioned this in the last module and that is nested paths and expressions. We already looked at a simple property expression. What if that property was actually an object with its own properties? The method proposed in the Mustache spec is to use a block expression and then reference the property inside the block. This syntax isn't overly cumbersome at first glance, but what if you need to go deeper, a few properties deep or even farther? It can get pretty crazy, possibly even opening worm holes to other dimensions. So, to simplify this and practice dimensional safety, Handlebars introduces dot and bracket notation for your properties and expressions. This means you can reference child properties the same way you would in JavaScript. The example from the last slide is much simpler to implement in Handlebars with nested paths, as you can see.
Localization with Handlebars
Now that we've learned our first piece of Handlebars syntax, let's use it by converting some of our application to using Handlebars expressions. Our first task will be to localize our web application. Handlebars enables this easily when using it to render all the text on a site. Your localized text can be dynamically pushed into the page. The demo application starter code is what we'll begin with. You should have already pulled this code down into a local directory so we'll begin there. Open index.html on your browser first just so we can see what we're working with. One caveat here, opening HTML files from your file system with any version of Internet Explorer will give you problems. Later in the course we'll use local storage, which IE has turned off when loading HTML files from the file system. For this course, I suggest using a different browser for development. Vivaldi, Chrome, or Firefox will all work fine. Our first task will be to localize this site and have the language be dynamically rendered. We will be changing metadata in this site. In this clip, we will be templating this text that is highlighted. Now, open index.html in your text editor. We are going to take basically our entire viewable page out and move it into a template. This way we can easily swap out the language when needed and re-render the page. There are many ways to store templates for Handlebars. We will use one of the simplest and store our templates inside a script tag in the same index.html. On line 15, we see the root element of our entire site. If you were to collapse the div block like this, you'll see that it is indeed all of our visible HTML. This element we want to keep because it will give us something to render our HTML into. Also, Material Design Lite needs those root elements to initialize some UI magic. So, we will keep it there and add an ID to the element so it will be easier to select and insert finished HTML into. Add an id attribute and assign the string main to it. Now, we will extract the HTML from inside that element. So, select it all and cut the HTML out from line 16-145. Leave that on your clipboard for a bit and create a script block at line 17. This is where we will store our template. Go ahead and paste the extracted HTML into it. Because this HTML is inside the script tag your browser will actually not render it at all even if it is HTML markup. How convenient. Now, give this script tag a type of text/x-handlebars-template and an ID of index-template. The type doesn't actually matter that much, but if you're using Atom like me it will give you some syntax highlighting inside the script block where before it was gray. Now we have our first template complete. If you were to look in your browser you'd only see a white screen because the template is not being rendered. Let's get that set up now. In the js directory of your project, create a file called app.js. This file will contain all of our application code. I've already provided you with some helper code in the dogPack.js file. When needed, all of that code is stored in the dogPack global variable. Our first step will be to get the template into a variable. Since we'll be working here, let's go ahead and create an immediately invoked function expression to keep our global scope clean. Inside this, we'll create a function called renderPage. We'll implement this function to render the entire body of our site. First, declare a variable called template and use jQuery to select on the index-template ID. From this element, we'll use the HTML function to extract the HTML from that script element, which is our template HTML. We'll also declare another variable called compiled. Use the Handlebars.compile function and pass in the template variable. This will take the index template, which is just a string right now, and compile it. Now we can actually do some rendering. So declare one more variable called rendered. Here, we'll use the compiled function that Handlebars created to render our HTML. We want to change render languages so we do need to pass in some data. In dogPack.js, I've already executed a function to initialize the page with a language. I've stored everything you need in a language global property. Pass this in to your complied function. We don't have any Handlebars expressions in our template yet so this rendered variable will contain the exact contents of our index template. Let's insert this into our main element. Use jQuery to select on the main ID and then call the HTML function on the element. Passing in rendered as the argument, this will insert our rendered HTML into the main element. Finally, we just need to call the renderPage function to get things going. You can do this at the top of the file here. While we're in JavaScript, lets go ahead and hook up the language switch button. At the bottom of the renderPage function, use jQuery to select the element with a languageSwitch ID. This is the button in the top right corner. Use the jQuery click function to add a click handler and then define an anonymous function as the argument. I've already got all the logic to switch the language and refresh the page in DogPack, so here just call the switchLanguage function on the DogPack namespace. Now, our language button will refresh the page in the other language. You may be tempted to pop over to the browser and see all of this in action, but let's use Handlebars a bit more by putting some expressions into our index template. Open up index.html again and find your index template at line 17. Our first templating step will be to change the site title in the upper left-hand corner. On line 22, remove dog or not? and replace it with a Handlebars expression. Here, we'll render the property siteTitle, which is on the language object that we passed in. Next, we'll replace some menu filters from the top right of the header. On line 30 all the way over to the right, you'll find the first one where it says Dogs. Replace that with a Handlebars expression and the property dogsFilter. Not Dogs will be replaced with the notDogsFilter. Maybe Dogs will become a Handlebars expression with the property incompleteFilter. We'll skip the score stuff because we will handle that later. On line 46, you'll see the text for the language switch button underneath the menu. Replace dog? with a Handlebars expression and the languageFilter property. Our last replacement will be the main site title, which you can find the text for on line 52. This will be replaced with a Handlebars expression and the siteTitle property. Hey, didn't we already use siteTitle? Yes, we definitely did on line 22. Why use the same property? Well, if you decide to change the title of your site you only need to change it once, which is pretty nice. That's one of the many features that will make you love templating. Well, we've completed templating our index page. We skipped a few pieces because we'll be templating them later. Go ahead over to your browser and refresh your index.html page or open it up. If you changed everything correctly, you should see absolutely no change in your site. At the most, you might have noticed a split second of a white screen when refreshing. Other than that, it should look the same and users will never be able to tell the difference. Click the language switch button which says DOG? in the top right corner. The page should refresh, and now we see the page is in dog language. You can click back and forth between the languages and marvel at what a little JavaScript can do. In the next clip, we're going to tackle the dog rendering and learn about iterating in Handlebars.
Iterating Through Arrays
I've talked up helpers quite a bit so far, but we'll wait until next module to get deep into them. Handlebars does ship with some built-in helpers however, and we will cover those in this module. One of the most used helpers is each. The each helper is used to iterate through arrays or objects. The each helper takes a single parameter, which is the object or array to iterate over. Inside the each block, the context becomes the current element that is being iterated over. Here's an example of using each with an array. Assume that you passed in a property into your template called dogs. Dogs is an array with a few names of dogs as strings. To iterate through these, you would call the each helper and pass the dogs property as the first argument. Close the each block with a forward slash. Inside the each block, you would reference the current element with the this keyword. In the case of an array containing strings, this would output the contents of the current string. And your output would look just like so. But wait, there's some weird stuff here. What's that hash sign? What is this argument doing in a Handlebars expression? Let's cover a few points before going any further. Beginning a Handlebars expression with the hash symbol indicates that you'll be creating a block. Handlebars blocks begin with an expression with the hash symbol and end with the same expression except starting with the forward slash, similar to HTML. The first property after the hash and forward slash must be the same. This is how Handlebars matches up the opening and closing elements. You can make a block with a single property like an object, and the context inside that block will be the object itself. With the built-in each helper, the hash is used to create a block that will loop for each element in the passed array or object. I also mentioned arguments. Handlebars helpers are able to have arguments passed into them. The first argument of a Handlebars expression is the property or helper name. So, a Handlebars expression to render a single property like our site title would have only a single argument, which is siteTitle. Handlebars would find the data for this property and render it. If the first argument is a helper instead then it will take other arguments in the expression, each separated by a space. We'll do some work with custom helpers and arguments in the next module. And for this module, when I say argument in the context of a Handlebars expression that's what I'm talking about. Alright, back to it. What if we're iterating through an array of objects. This is just as simple as the last array example. On each iteration the context inside the each block is the current element. You can reference properties on the object simply by using the property key in an expression. With the following data example, we could output the name by just using the name property. The image property could be input inside this image tag just like so. You can explicitly use the this keyword to validate these properties, but it's not required. Now that we know how to iterate through an array, what could we do with this knowledge? Well, we've got a total of around 20 dogs that we want to show in our site. Each one has the exact same markup except for a few data points. Looks like a perfect candidate for an each block. So let's go into index.html, and we're going to make a script block to store our dogs template. So, insert the script tags at line 149. We'll give this the same type as above, text/x-handlebars-template, and an ID of dogs-template. Inside this expression, we're going to use an each block. So, create that. The argument for the each expression will be dogs, an object we aren't passing into our template just yet. Now we need to get the markup. In the index template at line 54, we see a div with ID of theDogs. This is our parent div for all the dog elements. We will eventually want to render into this div. For now, look at the first child element below it. On line 55, there is the start of a div block with the class dog-card. This is the HTML to represent one of our dogs on the screen. If you scroll a bit down, you'll see that this markup is replicated multiple times with different data. We will extract the HTML for a single dog and use that in our template to render all the dogs dynamically. Copy lines 55-67 and paste the template inside the each block of our dogs template. When dealing with Handlebars tags in HTML, I typically indent as if the Handlebars segment was an HTML segment. This can sometimes get a little weird with ifs and elses, but generally works out fairly well. With the markup for our dog-card entered in the template, we can now swap out the data points for Handlebars expressions. On the right, here is the data structure for each dog. This is defined and set up in the dogPack.js file. First, let's take the ID value on line 151 and replace it with a Handlebars expression in the ID property. In the style attribute on line 152, you'll see that the background URL is set to an image. These are all in the images folder of the starter code, and each dog object has an image property for the JPEG that corresponds with that dog. Replace goofy_dog.jpg with image and a Handlebars expression. And in the next line, swap out Goofy for a Handlebars expression with the name property. The next two Handlebars expressions will be in reference to our localization and won't actually come from our dog object. We will be passing in the global language object when we render the dogs template, but how do we reference an object at the root context inside an iteration of an each block? Well let me introduce you to the first @data variable that we'll use for Handlebars. @data variables are used by Handlebars to signify special properties to be used in built-in Handlebars helpers. To get the root context of an each helper while inside an iteration, use the @root variable. This will allow you to access the initial context that the template was rendered in. This can be especially useful when we want to access the language property. On line 157, replace dog with a Handlebars expression. Inside this, we'll insert @root.language.yep. In this way, we access the language property that was part of the initial calling context. Replace line 160 with the nope property on the @root.language object. Our template is complete. Great job. Let's get rid of all the dog markup inside our root dogs element. Delete the HTML from line 55 to line 132. You should be left with a single div with the ID of theDogs. This is where we will render our dynamic dogs. Let's go ahead and write the code to render the template. In app.js, we'll first call renderDogs, which is a function we'll build below. On line 4, call renderDogs below renderPage. On line 17, declare the function renderDogs. This is where we'll put all our logic for rendering our dogs template. We'll do our Handlebars dance like we did in renderPage by first getting the template. Declare the template variable and use jQuery to get the HTML from the element with ID of dogs-template. Next, we'll create our compiled variable and call Handlebars.compile with our template. The last piece will be our rendered variable. Call the compiled function, and into this we need to pass two separate variables to be rendered, dogs and language. To do this, create an object literal and give it two properties. The first is dogs, to which we'll give the value of DogPack.dogs, the dogs that I've initialized for you already. The second property is language to which we'll set window.language. This will render our template with the correct data. Our last step is to insert the rendered HTML into our page. Use jQuery to select on the element with ID theDogs. Then, set its HTML to a rendered variable. Now, let's check out our work in our browser again. If you reload the page, all of our changes should be run and our page should work. It looks good to me. If I scroll down, I see a whole lot of dogs just as I had hoped. This means we're rendering all the dogs that are in our dogs object, which is good for now.
Logic for your Logic-less Templates
One of the key tenants of the Mustache spec, its tagline if you will, is logic-less templates. Handlebars ships with the if/else helper functions, which gives your templates just a smidge of logic. Wait, you may say, doesn't this totally break Mustache? Isn't this heresy by Handlebars? Calm down. Let me explain. Mustache actually does define all the mechanisms to make something like if/else work. By this I mean Mustache also has just a smidge of logic, a Mustache block section where the property looks like this. The templated expression inside will only execute if that property exists. So, if it exists then the template inside will execute. Next, a Mustache specification also defines an inverted section, which is basically the opposite of the if block. If the property doesn't exist then execute the code in the block. These two structures are basically an if/else structure. It is limited to the existence of properties or Boolean properties, but it is still fundamentally a piece of logic. Handlebars doesn't beat around the bush, and instead it just gives you what you want with an if/else helper. I believe this is an acceptable amount of logic in your templates and when used correctly will only help to separate your application logic from your template. Let's look at the syntax of an if/else block. The Handlebars expression begins with a hash sign. Then, the first argument is the if helper. The next argument is the property or Boolean to check for truthiness. The following templated code will render if the argument is truthy until a closing if expression or else expression is found. This is what a basic if block looks like. The if helper is limited in what you can check for truthiness. It only accepts one argument so you're not able to do any comparisons or operations. You can only check one property and the check is its truthiness. In the past, I've implemented more complicated if statements, but I've always had to use helpers to accomplish it. I also ended up questioning why I needed such complicated logic and ended up refactoring it out later back into the application code. Sometimes this limitation to what can be compared will actually help guide your software design decisions. Else adds another dimension to your if blocks. When entering the expression inside an if block, it will render the template after an else expression if the argument evaluates to falsy. Here's the previous example with an else expression giving us an alternate section to render based on the state of the object. Else can also be used with the each helper. If the argument to an each helper does not exist, the template markup after the else expression will be rendered instead of what is above it. Here's an example of an each block for dogs and the message that the else block would show if dogs evaluates to falsy by either being undefined or if it's an empty array. Let's take the if/else helper for a spin with our application. Switch over to your text editor and open up the index.html file. In our dogs template, we are iterating over a dogs property, but what if there are no dogs? Well we shouldn't have that situation yet, but once we add filters it will become a possibility. So let's add an else expression to our each and print out a message if there are no dogs. After line 84, make a new line and add an else Handlebars expression. After this else expression we'll output the language.noDogsMessage property, which is a localized message. We don't have a way to test this out just yet, but we will later when we add filters. Now let's add a full if/else to our project. We'll hook up our DOG and NOT buttons to actually work with our application and use an if/else helper to give the user some feedback on their choice. First, we'll hook up the buttons to modify our dog objects. Open up app.js. One important thing to remember about rendering templates with Handlebars, if you want to have click handlers or interactions attached to DOM elements these handlers need to be set each time you render, not just at the beginning of the page load. Every time you replace the DOM with the newly rendered HTML the old click handlers fall off. So let's make a function that will set all that up for us. Call it attachDogButtons and define it after renderDogs. First, let's grab all of the dog buttons with jQuery and add a click handler. Inside the click handler, create an anonymous function. The first thing we'll do is to find out which dog was actually clicked. Declare an ID variable to store the dog ID. Then we'll use jQuery to select the element that was clicked and then move up the chain to find the dog-card element that it is a part of. This element has a data field on it that was populated by our template. Use the data function with the string dog-id to get this ID field. Now that we have the ID, pass it into the DogPack.chooseDog utility function. This will set the chosen property on the dog to dog. The last thing we'll do in this handler is to re-render our dogs. Call renderDogs here. Now we'll add our not dog click handler, which will look suspiciously close to the dog click handler that we just implemented. For this reason, copy the dog-button click handler and paste it below. Change the selecting class to not-dog-button. And instead of calling DogPack.chooseDog, change it to DogPack.chooseNotDog. I really hope you're impressed with my function naming skills. I do tend to go a little overboard. We're still missing something if you remember what I mentioned about attaching button handlers. If we just call renderDogs it will refresh our dog code, but the click handlers will be gone. So, add an attachDogButtons function call to the end of renderDogs so this action will happen every time we render our dogs. Alright, so we've got click handlers modifying our underlying data, our render functions are set up to attach all the click handlers so any time we see some dogs we will be able to evaluate their dogliness or lack thereof. Now let's use our if/else handler to display feedback to the user. Back in index.html, find our dogs template and make a new line at line 83. Here we will insert the user feedback on whether their selection was correct or not. Our first if block will determine whether a choice has been made or not for that dog. The chosen property will not exist if a choice has not been made. Create an if helper block and use chosen for the first argument. Anything inside this if block will only execute if chosen evaluates to truthy. Now, we will make our binary choice to determine if the user selected the correct option. All the logic to determine this is in our dog object so we don't need to know what's going on in our template, which is exactly how it should be. Create another if block and pass the isCorrect property as the argument. Go ahead and add an else expression as well to complete our helper structure. If isCorrect is true, we'll utilize a localized message by rendering an expression with the @root.language.correctInd property. If isCorrect is not true, anything after the else will execute. And here we'll output the @root.language.incorrectInd property. To add a little styling for each of these I've already created some classes we can apply. Around each of the tags we just added wrap them in a span block. And for the correct message use the result-good class. For the incorrect message, use the result-bad class. Now we're at a place where we can go check out our progress. Move over to your browser and refresh that puppy. Again, you should see no changes, which is good. We're changing so much structurally with the page we don't actually want the visuals to change. Now click on one of the DOG or NOT buttons, and based on your choice you should see a feedback message telling you if you're right or not. Go ahead and try out both right and wrong choices. I promise no one will judge or think you're stupid for saying a bunny is a dog. If everything is looking good go ahead and continue on to the next clip.
Modularization with Partials
A partial is a special structure in Handlebars. You can conceptualize it as basically a mini template. Anything that is possible in a template is possible in a partial, even rendering other partials. In use, partials are basically a mechanism to modularize reused pieces of a template. Throughout my experience using Handlebars, I've used partials for making my template smaller through modularization and for refactoring repeating template blocks. Let's look at both of those examples. Let's say I have a dog of the day widget in my web application. It renders an image of a shelter dog that you can adopt. I want to use this widget in my index template, my user account template, my search results template, all over the place. Instead of putting the markup for that widget in each page, I can put it into one partial and then render that partial on each page. Handlebars keeps global references to partials so you can use them anywhere with minimal impact. Changing the look or code of the widget would happen entirely in the partial template. The other typical usage of partials is to break up monolithic templates. Believe me, they can get long and complicated. Let's say you have a page template with a lot of different sections. Each section has a lot of conditionals and it can be difficult to find when one section ends and another begins. Breaking out sections of your template into smaller partials will help keep you sane and improve the maintainability of your templates. The steps to include a partial begin in JavaScript. The Handlebars API has a registerPartial function that is used to declare a partial. This function must be called before the template using the partial is rendered. The first argument to register partial is the name you want the partial to be referenced as. In this example, we'll name our partial dog. The second argument is the template for the partial as a string. Here, we'll just put some facts in the form of a template. The second part of creating a partial is done in your template. Partials are included by a regular Handlebars expression. They begin with a right-facing arrow, and then the first argument is the registered name of the partial. In the previous example, I registered the partial under the string dog so we'll use dog here. And that's it on how to include a partial. Now, one key thing about partials is that they are typically templates themselves with Handlebars expressions so the context when they are rendered is important. Partials receive the same rendering context that they were called in. Now that we know a little about partials let's implement one in our site. In index.html, find your dogs template. We have two things actually happening in this dogs template. One, we are iterating over an array or posting a message if it's empty. Two, we are rendering a single dog object. I want to separate these out so we can have a dogs template and a singular dog partial template. So let's do that. First, below the dogs template under line 95, create a new script block. Set the type to text/x-handlebars-template and the ID will be dog-template. Now, we'll copy the dog code from the dogs template. Cut line 72-91 out and paste it inside the dog template block we just created. On line 72, which should now be empty, we'll output our partial. Inside a Handlebars expression, enter a right arrow and then the argument dog. Before we move over to JavaScript, let's do one more thing. When including partial expressions, you actually have the opportunity to declare variables that will be scoped to that partial. This gives you a good chance to rename properties, set your own static properties, or re-reference parent variables. I never really liked the long syntax we had to use with the @root.language variable. I prefer to just be able to use the language property directly. So let's do that. Inside the dog partial expression put a space after dog. To declare a new variable for your partial start with the variable name. Enter language here, then an equal sign, and to the right of that is what will be assigned to the variable. Here, we'll enter @root.language. That's all you need to declare this variable. You could continue to declare more variables for your partial, just space delimit each declaration. Now that we can reference a direct language variable, remove the four @root data variable reference in your dog template. We are ready to register our partial so move over to app.js. At the top of the file, before renderPage, let's call a registerPartials function. We only have one partial, but I like the elegance of the structure. Above the function definition for renderPage, create a function for registerPartials. Inside this function, it's quite simple to register our partial. Call Handlebars.registerPartial, and the first argument is the string dog. And for the second argument use jQuery to select the element with an ID of dog-template. Call the HTML function on that to retrieve the template HTML. And that's all we need to do to register our dog template. Now, when we render our dogs template it should work perfectly. Let's try it out in our browser. Again, refresh and your application should look exactly the same. Only now you can sleep safely knowing that your dogs are being rendered as partials. Try out some of the controls just to make sure all your language expressions are being translated correctly. And that's it for partials. Next, we'll be checking out a few minor, but very useful features in Handlebars.
Escaping HTML and Removing Whitespace
Handlebars, by default, escapes HTML text when rendering it through expressions. This means that if you enter any special characters in a property Handlebars will convert it so special characters will be displayed as text instead of interpreted as HTML. This works fine for most scenarios like when you want an ampersand to look like an ampersand or want to output some HTML example for a Pluralsight class on Handlebars. But what if you want to output actual HTML? The default way of using Handlebars expressions won't work. Instead of a normal expression, you can add an additional set of curly braces around an expression and it will let raw HTML pass through. So if I have a property with this data that has HTML in it and I render it with a normal expression it will output like this with the HTML characters escaped. But if I use the triple curly brace expression then the raw HTML will output like so, which is exactly what I want. White space is another consideration when rendering Handlebars templates. With all the if/else blocks, iterators, and property rendering sometimes your rendered HTML can turn out a little, well, Frankenstein-ish. Luckily, Handlebars provides a very simple remedy for this. You can begin or end any Handlebars expression with the tilde character, and this will remove any whitespace or new line characters between the expression and the next non-whitespace character. You can liter these throughout your templates as needed or just go wild and put them everywhere. There is just one consideration with this, it only affects the rendered look of the HTML code, not how your site actually looks in a browser. You will likely be the only person looking at your HTML code so it's really only for your benefit. Still, having control over these types of concerns is a very nice thing to have. I don't have any exercises for these features so just keep them in mind when you're working on your own project as they might come in handy.
Conclusion
Great job making it through this module. I know syntax overviews can be a little dry, but honestly, we've covered most of the Handlebars syntax already. Let's review what we covered in this module. First, I introduced you to the demo application we were going to convert, and we installed our application dependencies with Bower. Then we went over basic Handlebars expressions and started the first conversion of our application by localizing much of the text on the site. We looked at the each built-in helper and started iterating through some dogs. You know, I just realized that I've said dog almost 150 times in this module alone. That's pretty cool. It's like some sort of Pluralsight record or something. Anyway, we learned that Handlebars stretches the logic-less rules a bit with the inclusion of if/else helpers. Then we implemented a partial and learned a few of its tricks. Finally, we looked at how to output raw HTML and handle whitespace in Handlebars, two very useful bits of knowledge. In the next module, we're going to go deep into helpers. They'll really bring our application to life and rival a lot of the functionality in most modern-day web frameworks. Helpers are pretty fun to work with and finding all the places you can use them can sometimes feel like an Easter-egg hunt. There are so many uses. We'll create several so you can feel comfortable using them in your own site. See you in the next module.
Harnessing the Power of Helpers
Introduction
Welcome back to JavaScript Templating with Handlebars. Now with 50% more dogs. My name is Ryan Lewis, and in this module we're going to become masters with Handlebars helpers. As you may remember me mentioning, helpers are the killer feature of Handlebars and expand the possibilities of JavaScript templating. In this module, you're going to get plenty of experience working with them. We'll start by looking at function properties, which give you a taste of what helpers can do. Then, I'll make the case for why helpers make your life easier by attempting to implement helpers ourselves. Then we'll look at four different types of helpers and complete our demo application development by using them. Let's get started.
Function Properties in Handlebars
Handlebars expressions are typically used to render properties such as numbers or strings from objects into a string. We've done this several times in the last module. But what if you had an object and there was a property that was a function, would Handlebars print the contents of that function definition? What Handlebars will do is execute that function property and output the result. You can even pass arguments into that function property. Mind blown, am I right? This is huge and expands the bounds of what we've been doing with templates. What's the most surprising of this is actually a feature of Mustache defined in the specification. The best thing about this feature is that you already know how to use it. In the last module, we used a function property when rendering feedback for our dog. The isCorrect property on our dog is a function that tests the equality between its isDog Boolean value and the chosen property. It returns a true or false value, and because of this we were able to easily use it in a Handlebars if helper. The great thing about keeping application logic in these member functions is that the function is dual purpose. You can use it in templates because it's a part of an object that you have access to, and you can also use it in typical JavaScript usage, as well as being able to unit test it. It's sort of a best-of-both-worlds approach. Since the execution of function properties is part of the Mustache specification, Handlebars doesn't bring anything new to the table here. Handlebars instead adds the addition of helper functions, which are also callable functions and templates, but they're scoped at a global level and accessible from anywhere in your templates. In the next clip, we'll look at just how much developer pane helpers save you from.
The Case for Helpers
Youmightnotneedjquery.com was a site launched back in 2014. It gave API-level examples of using vanilla JavaScript in place of jQuery. By showing how you could achieve the same functionality without using the jQuery utility library, the site attempted to convince readers that using vanilla JavaScript might be better. The usual comment wars started up discussing both sides, but what stood out to me was just how much jQuery was actually doing for developers. It also increased my appreciation for what jQuery was saving me from. These days, it seems like we often use third-party libraries without considering the difficult language gymnastics that they simplify for us. I bring this up because helpers in Handlebars are a smooth way to accomplish an annoying task that is technically supported in the Mustache specification. At the same time, helpers introduce a powerful design pattern that shapes the way you build your sites with Handlebars. I'd like to first present a way to implement the equivalent of helpers without actually using them. This would fit into the Mustache specification with ease, but hopefully the difficulties will become apparent. Helpers provide global references to JavaScript functions that take arguments, as well as templates, to provide some rendered output. As discussed in the last clip, Mustache already provides the mechanism to call a function property. But the difficulties arise when you attempt to make a function property globally available and in any context. Let's start at the top. Say we had a function, call it formatMoney, which takes a number and formats it to two decimals, adding the localized currency symbol. This function needs to be available at all levels of the site and will be used all over the place. We'll implement this function at the global scope as a property on the window object. For every template we render we would need to pass this function into the context of the template. Then, it would easily be accessible at the top level of our template. Not so bad. Now, let's say we're iterating through multiple objects. Well, in each iteration we couldn't use formatMoney. We would need to somehow reference the parent context to access it. Handlebars gives us the @root data variable, but vanilla Mustache doesn't actually specify any way to do this. We would have to add the formatMoney function to every object we were dealing with. Ouch. That starts to look really messy on our JavaScript side. Let's look at how we would call our formatMoney function. Since we need to pass in arguments, we would have to use a block expression with the formatMoney function property. Then the argument for the money number would go inside the block. Three lines just to get some formatted money. That's going to make your templates pretty long. I'm not even sure partials could help you out there. Implementing something like this is a total headache and the effort is definitely not consistent with the gains. And this is where Handlebars helpers comes into the picture, simplifying this entire operation down to a single function call and an expression format. In the next clip, we're going to take a look at how to implement helpers and feel thankful we don't have to revisit implementing them ourselves.
Simple Helpers
Helpers are Handlebars' killer feature that enable you to do more with your templates. I think I've talked it to death at this point so let's just start looking at what it takes to bring a helper to life in your code. Helpers are originally built in JavaScript code. They are essentially functions with parameters. We can see that in this basic function declaration. To register this regular function as a Handlebars helper, the Handlebars API provides a registerHelper function. Once registered, this helper function will be available globally throughout your site. The registerHelper function takes two arguments. The first is the reference name for your handler, how you'll refer to it in your template. And the second is the actual function. Helpers can receive arguments whose structure and number are up to you. A helper receives the context from which it is called in the this keyword. So, sometimes you don't even need arguments. However, relying on the this keyword for arguments can make it difficult to test your helper function so be mindful when building them. There are two things to watch out for with Handlebars Helpers, therefore, I have a very minimal slide with only two bullet points. You must register a helper before using it to render in a template. You can compile a template before the helper is registered, but attempting to render will throw an exception and render nothing. Also, watch out for naming collisions with properties. In Handlebars, the helper registry is checked first when resolving a Handlebars expression. If you have a local property key that matches an existing helper reference then Handlebars will render the helper instead of the property. You can avoid this by validating your property expressions with the this keyword. But that will get quite tedious when using it for every property. My suggestion is to just name helpers and properties differently, thereby avoiding the whole conflict thing altogether. When using helpers in your templates, there's no special syntax or characters needed, just a simple Handlebars expression with the helper name. Any arguments you want to pass to your helper would be space delimited after the helper reference. This example here shows a helper with multiple arguments. Let's do a simple exercise with helpers. It will make it easier on us to keep our helpers in a file all to themselves so create a new file in your js folder and call it helpers.js. Then, open up index.html. We need to include the new helpers.js file before app.js. That's important because our templates compile and render in app.js and the helpers need to be registered before they are used. After line 102, create your script tag and set the source attribute to js/helpers.js. Now, open up helpers.js. The first helper I'd like to create is the helper for our dog. This helper will add a class to highlight whichever DOG or NOT button has been selected. We can wrap this up in a helper and pass in an argument, letting us use the same code for both buttons. Call the Handlebars.registerHelper function. We'll call our helper isChosen so set that for the first argument as a string. The second argument will be an anonymous function with one argument. Call it type. This type argument will let us tell the helper whether it is a DOG or NOT button it's being used on. The helper function itself is going to be pretty succinct. First, use an if statement to compare the equality of the type argument and the this.chosen property. Remember, inside a helper the this keyword gives you access to the context where the helper was called. If we're calling this helper within the context of the dog then this is going to be the current dog. That means we are looking at the chosen property of the current dog and comparing it against our type argument. Chosen will either be dog or not or just undefined. Now, in the if block we will return a string if the if evaluates to true. Return the string mdl-button--colored, which is a class defined in the Material Design Lite framework. Now that our helper is registered we can use it in our templates. In index.html, find your dog template. We're looking for the DOG and NOT buttons that start at line 83. We'll be using our helper to output or not output an additional class that will change the styles for the button. Remember, we can use Handlebars expressions anywhere inside a template since it's all just a string to Handlebars. Inside the class quotes for the dog-button element create a Handlebars expression. This is where we'll call our helper. The first property is the name of our helper, isChosen. The argument for the helper should be the type we want associated with this button. With single quotes here, enter the string dog. You can also use double quotes, single quotes are just a preference of mine and may be more readable inside the HTML double quotes. That's all we need to implement this helper. Three lines down in the opening tag for the not-dog-button, add the same helper inside the class attribute. For the string argument enter not dog with a space between each word. Now, both of our helpers are implemented for this feature. Let's take a look in our browser. If you've already selected some dogs you should see immediately results from your choices once you've refreshed, with the selected button highlighted in dark blue. If you make a few selections, you'll see your choices updating almost instantly. Since we're re-rendering the template after each interaction, the helper is reevaluated with each render.
Dual Citizenship Helpers
We've discussed how helpers are global to your template, but you can actually reliably use them in JavaScript as well, making them more useful than ever. Once a helper has been registered, Handlebars stores it in the helpers property on the global Handlebars object. Since it's accessible on all of your JavaScript, you can use it anywhere in your code once the helper has been registered. We're going to create a helper to generate the correct language filter to be applied to a URL. We'll use this when building some links in HTML and also in JavaScript. Let's create the helper first. Open up helpers.js and call Handlebars.registerHelper. We'll call our helper getLanguageFilter and define an anonymous function for the second argument. Our anonymous function will take one argument, let's call it langId. This will be populated in our template from dynamic data. Inside our function, we will very simply compose a string and return it. Start by defining a variable called queryParam and set it to an empty string. Create an if block and test the existence of the langId variable. If it exists, we want to set queryParam to the concatenation of the string &language= and the langId argument. This will be able to be easily appended to an existing URL. Outside of the if block return queryParam. But if you remember in the last module Handlebars escapes HTML and special characters when rendering expressions. So, if we return the string we just created it would escape the ampersand and screw up the URL. Could we use a triple curly brace solution like we can with a normal expression? Unfortunately, the helper output also escapes any special characters so the ampersand would be escaped before it even reached the magical three curly braces. Handlebars provides a nice construct to remedy this with SafeString. Handlebars SafeStrings do not escape HTML and ensure your special characters and HTML markup are rendered as intended. Return one by using the new keyword and the constructor function, which is Handlebars.SafeString. Pass in the text you want to be kept saved as the argument, which is our queryParam variable. Since our helper won't be escaping any special characters now, we should probably make sure that our langId argument is clean. Handlebars provides another simple utility method to accomplish this. On the line where we're building queryParam, instead of just concatenating langId, pass langId into the function Handlebars.escapeExpression. This will escape any special characters coming in from our langId. With our helper registered, we can start using it in templates. Open index.html and find the menu options on line 30. We have three filters we can apply to our dogs, and activation of these is with a simple link. The current URL is adding a filter query parameter. What we want to do is maintain the language when the user selects a non-language filter like these dog selections. We'll use the helper we made to do just that. In the href attribute of the first dog filter, after the filter=dogs, add a Handlebars expression inside the quotes. Inside this expression, call our getLanguageFilter helper. The argument to this helper will be the existing langId of this site, which is accessible in the current context. Enter langId into the expression. That's all we need to do to add this language filter. Add that same expression to the end of the next two hrefs below it. This will seamlessly keep the site language consistent by using the correct URL for each filter. Before we go admire our changes let's now use this helper in a different context. We have a reset button in the score box that is currently not doing much of anything and I'd like to hook it up. Open up app.js and go to our renderPage function. Below our languageSwitch click handler, we want to set up a click handler for the reset button. We can do this by using jQuery and selecting on the element with ID of score. Append to that the find function and pass in small, referring to the HTML element. This will select the reset button. So now, call the click function and pass in an anonymous function. Here we'll do two things when resetting the score. The first is to call the DogPack.clearDogs function. This resets all of the chosen states of each dog. Once that is complete, we want to return the user to the root page. We'll directly manipulate the window.location.href property here. So, set that to the left-hand side of an assignment. On the right, start with the string ? then we'll add our Handlebars helper. Call it by typing Handlebars.helpers.getLanguageFilter and then passing in window.language.langId in parentheses. Now, all helpers won't work this smoothly in JavaScript. We'll learn of a more complex helper in a bit that requires templates. However, when you have good knowledge of a helper you can make use of it in both contexts. One consideration is that helpers are built to do one specific thing, which is render in templates. It might be a cleaner implementation to just refactor out the getLanguageFilter code into another function and just call it in the helper. Still, I think being able to use helpers in both contexts is pretty cool. And I wanted to give you just a taste of it. You can decide the best way to use them in your own projects. Let's move over to your browser to view the changes. First, refresh your page and then make sure you have some dogs selected. Click the RESET? button and your page should refresh and any choices be gone. Make a few more and watch it all wash away. Great. Now let's test the language filter on our menu filters. We haven't implemented the menu filters yet, but we can watch our URL to ensure the filter is working. Click a menu option and the language query parameter should update or maintain to the currently viewed language. Click on the language filter button to switch languages and then try the menu options again to ensure it's maintaining the correct language. In the next clip, we're going to get a little post-modern and use helpers inside of other helpers.
Helpers Inside Helpers
In this clip, we'll implement pagination in our application and use subexpressions, which are basically helpers inside helpers, to accomplish the task easily. Subexpressions are used exclusively with helpers and let you do more with a single expression. Inside any normal expression you can use parentheses to have Handlebars process an expression first before passing it to the next helper. In this example, we're taking a monetary value and executing an applySalesTax helper before passing it to our formatMoney helper. I just love how clean subexpressions can make things. Let's implement pagination in our application. There will be two sides to this. The first is to dynamically render the right dogs based on the query parameters. The second is to render the page-numbered links below the dogs. Right now, we still have all the dogs on one page and maybe in this world of infinite scroll that's the desired user experience. But gosh dang-it, pagination makes such a great example to use that we're going to implement it here. Besides, aren't technical decisions supposed to decide the user experience? I'm only joking. Please don't kill me UX designers. Let's start by filtering the display dogs. There are no helpers involved in this so you'll get a little break from them for a bit. Open app.js and find your renderDogs function. Currently, we're passing in the pure DogPack.dogs object into our template. We actually need to filter the dogs for our menu options, and then we want to filter them for pagination. Two filters, you ready for it? Below the compiled declaration add a new variable called filteredDogs. We'll do the dog not-dog filter first so call the DogPack.getFilteredDogs function and pass in DogPack.dogs. In the next line for the object literal argument in compiled, we want to paginate filteredDogs before passing it in. Remove the DogPack.dogs value in the object literal and instead call DogPack.getPaginatedDogs. Pass filteredDogs into this. Now, our template will be rendered using our double filteredDogs. Pretty cool. It's time to get back into helpers. We're going to build a helper that will output an array that can then be iterated over with an each helper. All of this will be initiated in a partial template, which we'll build first. So let's move over to index.html. We want to declare a pagination partial that will make it simpler to include in our page. Under your dog template, which ends at line 98, create a new script block. Add the text/x-handlebars-template type and an ID of page-template. Now, scroll up to line 55 where we have a div section with ID of pagination. This is our current section to display the page links at the bottom of our site. We'll move everything inside this section into our template so cut lines 56-61 out and clean up what's left. Now take what's on your clipboard and paste it into the page-template block. Inside our unordered list, you can see we have a certain structure for each list item. We want to keep this same structure when we iterate through our pages. Under line 93, create a Handlebars each helper expression. Don't worry about the argument for now. Close it under the first list item and then delete the remaining list items. In this list item template, we have two pieces of data that we want to replace, the href attribute and the number text. Replace the href value inside the quotes with a Handlebars expression with the argument of link. Then, replace the number 1 with a Handlebars expression and the value number. Now we need an object to iterate over. We don't have a static property containing the page numbers so we need a way to dynamically generate all the page data. To do this, we'll use a custom helper called inside a subexpression. After the each helper, open parentheses. Reference our future helper, and we'll call it generatePages. It will take one argument, which is the current dog collection so add dogs after the helper. Now, believe it or not, our subexpression is complete. Handlebars will execute this subexpression helper first and then take the output and pass it to the each helper to iterate over. Let's go write our helper so we can see this in action. Open up helpers.js, call Handlebars.registerHelper, and pass in generatePages as our first argument. The second argument should be an anonymous function which has a single argument, which we'll call dogs. In this helper, we'll take the number of dogs passed in, calculate how many our screen can hold, and then dynamically create an array of objects with link and number properties to be rendered. First, let's create a couple of variables we'll use. Declare an empty array called pages and a not yet defined variable called link. Now, declare another variable called pageCount. We'll calculate how many pages we should have here. This is a simple division. Divide the dogs.length property, which is the number of total dogs, by the DogPack.getNumberOfDogs function call, which calculates how many dogs can fit on a screen. This may turn out to be a non-integer number so wrap this entire equation in the Math.ceil function, which will round our number up to the nearest integer. Now, all our variables are declared so we can start filling up our array. Create a good old for loop. Declare an iterator variable called i that starts at 1, loop while i is less than or equal to pageCount, and iterate i after each cycle. Inside this for loop, we'll build an object with number and link. First, we'll create the link so set up a link assignment. And to the right, we'll start by using a function on DogPack.generateUrlParameters. Into that function call pass the string page, which will exclude that query parameter from being returned. Calling this will ensure that any filters or language selections are maintained after switching pages. Concatenate to that the string page= and then our i variable. This will give us the right URL to change the page. In the next line, we'll push an object literal into our pages array, set the number property to i, and the link property to our link variable. Finally, outside our for loop, return pages. Once this helper is evaluated, this pages array will then be iterated over with our each helper and displayed on our page. We have our helper, we have our template, now let's set up the JavaScript to render them together. Open app.js. Create a new function under renderDogs called renderPages that takes one argument, which we can call dogs. You know what time it is, time to cut a rug with our Handlebars dance. Grab our page template, compile it with a Handlebars.compile, now render that sucker while passing in an object literal with a dogs property with the value of dogs. Finally, use jQuery to select the element with ID of pagination and set rendered to by its HTML. Nice moves. Now we just need to call this function every time we re-render our dogs, which will be the last thing we can do in our renderDogs function. Don't forget to pass filteredDogs into the renderPages call so there's some dogs to count. Move over to your browser and refresh it. If you scroll down, you should see your page has lost quite a bit of its height. You'll probably also notice that the links for pages on the bottom right don't seem to have changed. Click 1, however, and you'll see that they really have. And your dogs change as your pages change. In the next clip, we'll be taking a look at block helpers and complete the last changes in our application.
New Helpers on the Block
The last helper we'll create will be used to generate our score section. We'll actually be building a block helper, the fourth and final form of helpers we'll learn. You've already used block helpers like each and if/else, but this is the first that we'll create ourselves. The block helper syntax begins with a hash symbol followed by the name of your helper. The same block is closed with a forward slash and that same helper name. Block helpers are unique because they can only receive one direct argument as shown. There's a way to add more arguments, but they're added in a hash pattern. This example shows two more arguments being added. Inside the block helper will be some type of template that will be passed into the helper function. On the JavaScript side, block helpers are also special. They receive a specific set of arguments. The first is context, which will be the argument you pass into the helper in your template. And the second is options, which is built by Handlebars for block helper use. Options has a few properties that you'll use regularly. The first is a hash property, which holds any hash arguments. We'd use this format to access the hash arguments from the previous example. The other property on options is a function called fn. This is a compiled Handlebars function containing the inner template code from our block. Your helper can use this function to render out and return a string after doing some logic. Here's an example returning the result of an fn function. Let's build the template first. In your index.html file, create a new script block under the page template. Give it our Handlebars type and an ID of score-template. We'll be copying existing markup from above, but let's build the actual helper structure first. Start a Handlebars expression and add the hash symbol. Now, we reference the name of our helper, which we'll call generateScore. After a space, we'll pass in the context for our block helper, which will be dogs. We will also need to localize some values. So, let's pass in language in the hash format, add a space after dogs, and put the key as language, then an equal sign, and then the variable language. Now let's close our block helper. In another Handlebars expression, start with a forward slash and then enter generateScore, which closes out the block. Nice. Now let's get the inner template structure from our HTML above. On line 37 begins a div block with the ID of score. This has all of the markup for the little score block in the top left corner of our application. We're going to cut out everything from inside that div block and then clean it up. Go back to your score template and we'll paste it below our helper. We could put the entire HTML section into the helper, but I like to be a little more selective with what gets processed. Take the opening button element and move it above our helper block. The next three lines with numbers and types will go inside our block helper so cut and paste that. Great. Now with the inner text of our helper, we'll convert the pieces to Handlebars expressions. Change the first number to an expression with the property correct. Replace the word correct by creating another Handlebars expression that outputs the language.correct property. In the next line, we'll follow the same pattern to add Handlebars expressions for incorrect and language.incorrect. And then in the last line add two Handlebars expressions for incomplete and language.incomplete. Now, we've got our custom helper, some arguments, and an internal template. We're all ready to move over to JavaScript. Open up helpers.js, use Handlebars.registerHelper to create the helper we just used in a template. Give it the name generateScore and an anonymous function with our special arguments, context, and options. The helper function itself should be fairly straightforward. First, declare a variable called score, which will store our processed score. Then, use the DogPack.scoreDogs function, passing in the context variable. This function returns an object with correct, incorrect, and incomplete properties with the accurate sums. Now we're ready to return. After a return statement, call options.fn and pass in an object literal with four properties. The first is correct, and assign to it score.correct. Next is incorrect and score.incorrect. Then, incomplete and score.incomplete. The last property is language. To get access to this hashed parameter use the options.hash object and reference the key language with dot notation. With this, our generateScore helper is complete. Now let's render our score template and we'll be done. In app.js, create a new function under renderDogs called renderScore. It won't need any arguments. Now, it's time for our Handlebars dance. First, get the score template HTML and store it in a template variable. Next, compile that template and store it in a compiled variable. Finally, call the compiled function with an object literal and store the result in the rendered variable. The object literal will need two properties. The first is dogs, and the value will be DogPack.dogs, our root dog array. The next is language and will be assigned window.language. This context will give our template and helper exactly what it needs to render correctly. Finally, insert the rendered HTML into the element with ID of score. I hope the Handlebars dance is getting a little easier to remember. I warned you that we'd be doing it a lot, didn't I? Now we just need to call renderScore. We'll do this at the bottom of the renderDogs function since we want it to update every time the user makes a change. We did break one thing, however, with the addition of renderScore. At the bottom of renderPage, we're attaching our click handler to the reset button. Since we replaced the HTML with the renderScore function, it won't work anymore. So let's move that click handler down to the bottom of our renderScore function so the click handler gets attached correctly every time. I know it's taken awhile, but guess what our application is complete. That's right, we've implemented all the features using everything available in our Handlebars toolbox. In your browser, play around with choosing dogs, watching the score change. You can click some filters, click some pages, just go wild because it's fully functional. And pat yourself on the back, you deserve it. It really is awesome what we can do with a powerful templating library like Handlebars.
Conclusion
Congratulations on finishing your demo application. You've done a ton of stuff with Handlebars now, and I hope you feel comfortable working with the library and are already inspired for what you can use it for. Let's go ahead and recap what we covered in this module. I started by explaining how function properties work since they're sort of like Handlebars' second cousins. Then I made the case for why helpers were needed. We got a quick overview of the syntax pieces to create a helper, and then we implemented our first simple helper. We saw ways we can use helpers in templates, as well as pure JavaScript. And finally, we tried out a subexpression and then closed out our demo application development with a block helper. In the next module, we'll be finishing out the course by learning production-ready techniques for using Handlebars. So far, we've focused on embedded templates, but I'm sure you can see how difficult it will be to maintain that as your application grows. We'll use gulp, a Node-based build tool, to precompile our templates and then tweak our JavaScript code to make the most of it. Unfortunately, we'll be refactoring out our Handlebars dance pattern so re-watch this video a few more times if you still need to get rid of some energy. The next module is going to be awesome. See you there.
Beyond the Basics
Introduction
Welcome to the final module of JavaScript Templating with Handlebars. As always, I'm Ryan Lewis. And for this last module, we're going to peek behind the curtain of real-world Handlebars usage to understand how to take templating to the next level. On finishing this module, you should feel ready to begin using Handlebars in your sites for much profit. I'll start by talking about several ways you can get your Handlebars templates into your site, which can be more complicated than you think. Then, we'll go through the act of breaking up our demo application templates into separate files and set up pre-compilation with gulp. I'll give you a short run through of using Handlebars in Node. It's not really that different. And finally, we'll see what Handlebars is up to in the wild.
Loading Templates
So far in this course, we've put all of our templates into our index.html file as script elements. Retrieving them was as easy as a quick jQuery call. And we had fun, well I had fun, doing our Handlebars dance a lot. There're some obvious problems with this approach when implementing anything more than simple demos or walk throughs. First is the inability to share templates between pages. Sure, you can copy and paste between files, but that is so error prone you shouldn't even consider doing it. Next is that keeping templates in your HTML files means that it's that much more difficult to work in a team. If two devs want to work on different templates it means they're working in the same file instead of different files. There's also a logical split between each template, partial, and HTML file, which means that they really do belong in separate files. The final problem with this approach is small, but not unsubstantial. Mixing Handlebars in an HTML file means you get one flavor of syntax highlighting, which would be HTML. It's nice to have your Handlebars templates highlighted, and having them in separate files would accomplish this. Let's look at another way to load your templates into a site. Asynchronous template loading would pull in templates as separate files only when they're needed. It would happen in the background of the application and be mainly transparent to the user. Even though this sounds like a really efficient pattern, I haven't been able to find any third-party libraries that facilitate this and make it seamless. This means you would need to build the framework to support this asynchronous loading, which is definitely not trivial. Your presentation code would need to be able to wait for the template to load, which is an unknown amount of time. Also, relying on another connection for your templates means that any interruption is basically a complete outage for your site. With the rise of mobile browsing, you should plan to have your sites fail as gracefully as possible, and asynchronous loading of templates would make that very difficult. The final template loading method is my preferred method and the one we'll go through in the next several clips. This is template pre-compilation and loading. To do this, you would utilize some sort of build tool to compile your templates from separate files and concatenate them into one. Then, you can load this JavaScript file into your site, which would set up all of your templates ahead of time. This means you can edge this file and get blazing performance. And your templates are already in JavaScript, a huge performance gain over relying on the DOM. Node-based build tools like Grunt and gulp are particularly up for the task and they both have Handlebars plugins that make template pre-compilation simple. The only downside I can share is that large template packages may be slow to load for your users. Considering an intelligent build process that could produce page-specific template builds would make it more efficient and targeted. Pre-compilation's still my favorite way to package up templates, and it allows for each template to reside in its own modular file complete with nice syntax highlighting. In the next module, we're going to start breaking up our templates and create a production-ready build process for delivering templates to our site.
Gulp
Gulp is the JavaScript build tool that runs on Node. It's used for all sorts of purposes, everything from testing to file watching to application building. Gulp is structured as a core application with many different plugins for doing specific tasks. Gulp differentiates itself from its biggest competitor, Grunt, by utilizing streams during its automation tasks. This reduces the file IO, making gulp builds generally faster than Grunt. In addition, compared to Grunt's configuration-based automation approach gulp's pure JavaScript task building allows for better debugging and generally will feel more friendly to JavaScript developers. We'll use gulp to do our pre-compilation of Handlebars templates. I'll also show you how to set up gulp to watch for file changes, which will make developing with the build process very efficient. We'll start in our console to install gulp. There are two sides to gulp, a global install and a local install. We'll start with the global one. In your app directory, type the command sudo npm install -g gulp, which will install gulp globally so we can use the gulp command in our console. If you're on Windows, remove the sudo. Once it's finished installing, we'll get our local gulp install. Execute the command npm install gulp. Once that completes, we will have gulp both locally and globally. You can test it out with the gulp -v command, which will show both global and local versions, which is a nice convenience. Let's create a simple gulp file. We'll use this as the base for our final build script. A gulp file is basically the entry point configuration when running the gulp command from your command line. This is where all your gulp tasks will reside. In your main application folder, create a new file called gulpfile.js, all lowercase. Inside a gulp file, you're writing JavaScript to be processed by Node so just keep that in mind that this isn't client-side JavaScript we're writing. We'll start out by importing gulp at the top of the file. Create a gulp variable and require gulp. For now, we're just going to create a Hello world-ish automation task. Gulp organizes everything into tasks, which are named sequences of automation steps. When running gulp from the command line, you pass a named task for it to run and it will execute the function registered for that task. Call the gulp.task function. The first argument will be the task name. Enter hello here as a string. The next argument is the function for gulp to call. Here, just create an anonymous function that logs the string Hello world to the console. Save your file. And you've just created a simple, but fully functional gulp file. Let's test this out in the console. Execute the command gulp hello. This is the pattern for any gulp task execution. You should see some output by gulp on which task was processed and how long it took, which looks like it was a handful of microseconds. I told you gulp was fast. You should also see your Hello world output between the gulp output, proving that our task worked. Before getting started with splitting our template files, I want to set up our gulp watch task. This will watch for any file changes and a directory structure that we specify and run certain tasks when that happens. We'll compose our gulp tasks in a module pattern as well since that seems to be the theme for this module. Create a gulp directory in your root directory. This is where we will store the individual task files. And then just import them into our gulp file. Create a file in this gulp folder called watch.js. In this file, first import our gulp dependency and store it in a gulp variable. Next, we'll use the amd pattern to export a function for gulp processing. Do this by creating an assignment to the module.exports property. To the right side, create an anonymous function with no arguments. This code will set it up so that if any code imports this file as a module it will receive the function. Pretty cool. Inside the function, we'll do our watching. Call the gulp.watch function. It takes two arguments, and the first is the directory pattern to watch. The second is an array of tasks to run when something has changed. For the pattern, we're going to point to any .hbs files in our templates folder. Enter the string ./templates/*.hbs. The next argument is an array so go ahead and build that. Later, we'll create a templates task to precompile our templates, but we can go ahead and enter it here as the string templates. Our watch command is all set up for gulp. Let's register it as a task in our gulp file. In gulpfile.js, we first need to import the watch module we just created. Under the gulp import, create a new watch variable and require it with the syntax ./gulp/watch. We could create a new task, but we've already got our Hello world one below. It's basically useless now so let's rename the task from hello to watch. For the function, we imported that and it's stored in the watch variable. So, set the second argument to watch. Now we have enough of our watch to test it out so let's give it a shot. In your command line, type the words gulp watch to trigger the watch task. Gulp should output some text indicating it is executing the correct task and then it will wait for file changes. That's good. Go ahead and hit Ctrl+C to stop gulp watching the directory. In the next clip, we'll start on our modular template pattern.
Modular Template Patterns
Modular templates are easy to modify, enables syntax highlighting, and great for collaboration. Our next task is to extract each template from index.html and put it in its own file. Let's get started. First, we need to create our templates directory. This will hold all of our template files. Create it in your root directory. The first template we'll create is our index. So, create a new file in the templates folder and call it index.hbs. HBS is a typical extension used for Handlebars templates. I've also seen handlebars used for the extension. It doesn't really matter except for syntax highlighting since there aren't any applications that I know of that will execute a Handlebars file. Now, our file is ready so open up index.html. On line 17 starts the script block for our index template. In our Handlebars template we won't need the script tags anymore, just the markup inside it. Cut from lines 18-55 out. Then, paste that text into the index.hbs file. If you've already installed a Handlebars syntax highlighting package or somehow it comes by default with your editor then Handlebars expressions should start lighting up for you. If you haven't installed one yet, don't fret. There are plugins for nearly all popular IDEs and editors to highlight Handlebars templates. I'm using Atom for this course so I've installed Atom Handlebars to get syntax, highlighting, and snippet support. Now let's keep this train going. Head back to index.html and find your dogs template. Cut everything from inside the script block. Create a new file in the templates folder called dogs.hbs and then paste the dogs template into this file. Nice. Alright, our dog partial is next. Cut out the template from index.html. Now, because this is a partial we're going to name the file a little different. The convention for naming partials is to start them with an underscore. So create a new file in the templates folder called _dog.hbs. Paste the template code into the file and save. We're almost done. Just two more to go. Grab your page template out of index.html. Create a new file called page.hbs and paste the template into it. Back in index.html, grab the last template, which is score. Create a score.hbs file in the templates folder and paste the template into it. All of our templates have been cut out of index.html so let's remove the empty script blocks that are now unused. Wow, our index.html file is really small now. Well that's exactly what we wanted. By keeping our templates in separate files we can keep our actual HTML files very light. With our modular structure complete, our application is totally broken, but that's okay. In the next module, we're going to set up gulp to precompile all of our templates into a single JavaScript file that we can then include.
Template Precompilation with Gulp
One of the pain points when introducing a build process to your code is that it slows development time. This is certainly true with compiled languages like Java or C++, but JavaScript is a little different since there is no actual compilation process. Instead, we just need to combine our files and run a little code. With gulp watch, which we set up in this module, developing with this build process is an absolute breeze. Once we execute the watch task any changes to our templates will be almost instantly built and we only need to refresh our page to see any changes. Believe me, this makes a world of difference. Let's get our template pre-compilation set up so we can see this in action. We have a few dependencies to download first so open up your command line. This command will be a little long because we'll get all the dependencies in one go. Enter the command npm install gulp-handlebars, gulp-wrap, gulp-declare, gulp-concat, and merge-stream. Wow. That is a lot. So, npm will download all of these dependencies, and when it's complete move back over to your text editor. Create a new file in our gulp folder called templates.js. This will be the module we'll use for our templates task function. First, we need to import the many dependencies we'll use to make this magic happen. Import gulp into the gulp variable. Then we'll import the path library into a path variable. We'll import gulp-handlebars and keep it in a handlebars variable. Gulp-wrap will be stored in a wrap variable. We'll also use gulp-declare so put that in a declare variable. Store gulp-concat in a concat variable. And our final dependency will be merge-stream. Put that in a merge variable. With our imports out of the way, go ahead and create the structure of your anonymous function being assigned to module.exports, just like our watch task. We're going to have a pretty hefty chunk of code to get this all set up so I'd like to pseudocode it out first so it's easier to understand what's going on. Gulp works with streams so first we want to set up a stream for processing our parcels. We'll pipe that stream into Handlebars to precompile the parcels. Then, we'll use wrap to inline some JavaScript code, which will register our parcels. After the parcels, we'll start a stream for the templates themselves. We'll pipe them into Handlebars first for pre-compilation and then wrap them in JavaScript. Finally, we'll set each template on a global namespace with declare. Once we have both of those streams available, we'll actually write our return statement, which will merge both streams, concatenate them into a file, and dump it into a build directory. So, these are the steps for pre-compilation. I wanted to have us walk through it before I just started spouting code at you. But it's spouting code time now. Let's keep the comments since it might help with some comprehension. First, we'll create a partials variable. This is going to hold the partials stream. We'll call gulp.src to pull files from a source, and that will be the ./templates/_*.hbs. It will get any file in our templates folder that starts with an underscore. Don't end the statement and instead move to the next line under the comment and start with a dot. We'll chain several function calls together to create one statement. Call the pipe function and pass in a function call of the handlebars function. Under the next comment, call pipe again. Inside this pipe we'll call wrap. Wrap is going to wrap the incoming content in some text. Start a string and inside call the Handlebars.registerPartial function. As the first argument, we'll create a token for the file name by writing the string left angle bracket %=processPartialName(file.relative) % right angle bracket. I told you I'd be spouting some code. This token calls a function we'll set up in just a second. Now, we'll enter the second argument for the text-based registerPartial we're building. Pass in Handlebars.template and then another token with the value of contents. This is going to take the contents of the stream, which will be the precompiled template from our Handlebars plugin, and insert it into this Handlebars.template function, which sets up a precompiled template. Finally, add a closing semicolon after the parentheses, but still inside the quotes. The second argument to wrap is the data object, which we'll just pass as an empty object literal. The third argument is an options object, which we'll use to pass in the file name. Create an object literal. The only property we'll define is imports, which is also an object literal with one property, processPartialName, the function we called in our string. Give this a function as the value with one argument called fileName. Inside this, we'll return a JSON.stringify call. Inside the stringify call, we'll call the path.basename function, and that has a lowercase n, with fileName as the first argument and the string .js as the second. This returns just the part of the file name we care about. Finally, chain a substr function call to the end of the basename function call and pass in 1. This will remove the underscore from the partial name. Great. Our partial stream is complete, and we'll build all the JavaScript needed to register our partials. Next up is our template stream so declare that variable as templates and call gulp.src to pull from files. For the string argument for source, we want to get every template that doesn't start with an underscore so we can exclude the partials. To do this, enter the string ./templates/ open bracket, up arrow, underscore, close bracket, *.hbs. Sorry, that was difficult to read. This will just match our regular templates. Next, we need to pipe into the handlebars function call to precompile our templates. Then we'll pipe into a wrap function call and this JavaScript text will be easier than our partials. Inside a string, call the Handlebars.template function and pass in a token for the contents property. The final step in the stream is to pipe into a declare function call. This will set up our templates on a global namespace. Pass in an object literal. The first argument is namespace, to which we'll set the string App.templates. You can basically put anything here so if you want to name your global something else feel free. Next, we'll set the property noRedeclare to true, which reduces redundancy when setting our templates on this namespace. And now our template stream is done. Much easier than the partial stream, right? For the final piece, we need to merge the streams and output to a file. Start with a return statement and then call merge. Pass in our partials and templates variables. In the next line, we'll concatenate everything coming from either stream into a file. Pipe into a concat function call and pass in the string templates.js. Finally, we'll give gulp a destination to drop this file into. Pipe into a gulp.dest function call, and I'll be dumping mine into the ./build/js/ directory. You can send yours wherever you'd like. And that is our templates task. It took a while to go through the code, but we did some incredibly complex piping here and now we're ready to see the fruits of our labor. Let's open up our gulp file and register the templates task. First, import our templates file into a templates variable. Then, under the watch task, call gulp.task, passing in the string templates and then our templates code. We're ready to give it a shot. Move over to your command line and type the command gulp templates. You should see the starting and finished commands from gulp indicating that the templates task has completed. If for some reason finish doesn't output it means that something is probably wrong. You can use the gulp-debug library to find where it's breaking. The documentation has some steps to show how to use it. With our templates task finished, we can look at the output file. Take a look at the build/js/templates.js file in your text editor and, wow, yeah that is some gnarly code. Um, well scroll down a bit and we should see the global namespace getting set up and the declaration of our dogs template. You can keep scrolling and see that all four of your templates are getting declared. This looks pretty good. All of our templates are available. Now let's go modify our code to use these new templates. First, we'll include the templates file. Open up index.html. Our templates are used in app.js so create a new script block above that import statement and set the source attribute to build/js/templates.js. With our templates JavaScript being loaded, we can start using those templates in our app.js file. So open that up. We'll start by removing our registerPartials function since our pre-compilation process will take care of that for us. Remove the function call on line 3 and then the function declaration, which ends up at line 6. In renderPage, we can take a break from our Handlebars dance and instead use the index template on our global namespace. Remove all the variable declarations except for render. Replace the compiled function with our App.templates.index function. This is how to use the precompiled templates. In renderDogs, remove the template and compiled variables. Instead of calling compiled for the rendered variable, replace it with App.templates.dogs. In renderScore, remove template and compiled, and replace the compiled function call with App.templates.score. And our last change is in renderPage. Take out the template and compiled variables and replace compiled with App.templates.page. It's pretty amazing how much JavaScript that cleaned out. Let's go take a look at how our page is working now. Well, looks like everything is working smoothly. Nothing really different with the UI, but our templates are now being processed by our gulp build process, which is awesome. We didn't use our gulp watch task yet so let's go try that out. In the console, launch watch by executing gulp watch. Now, move to your text editor and change something in a template. You can add or remove a space or character or something. Now save the file and switch back to your command line. You should see output from gulp registering the change and running the templates command just as we configured it. This is insanely useful in actual development so don't forget to watch your files with gulp in your projects.
Handlebars + node
We've worked with Handlebars exclusively in client-side JavaScript so far in this course, but Handlebars performs equally well on the server side while running in Node. In fact, when we do our build with gulp Handlebars is actually running in Node to do that pre-compilation. I thought a concise little Hello world with Handlebars in Node might be a good way to end out this course. This won't have any relationship with our demo application, but you can use this same directory. First, let's install Handlebars via npm. Open your command line and execute the statement npm install handlebars. This is pulling down essentially the same JavaScript code that we import in our index.html file. Once it completes, we're ready to go. In your text editor, create a new file in your root project directory called node-test.js. We'll start by importing our Handlebars dependency and storing it in a Handlebars variable. You can make the Handlebars variable upper cased since it will visually replicate the client-side Handlebars global. Let's start by declaring some data that we'll process. Create a data variable and set it equal to an object literal. We'll add a property called message then the string Handlebars is good with: space. Add another property called places and assign to it an array. Add a few string values like the browser, node, and gulp. Now, we'll create our template to render this data. So, create a template variable. This template will be one big string. Start by outputting the message property in an expression. Then, we'll use an each iterator to go through the places array. You can use string concatenation to separate the template into multiple lines, which should make it a little easier to read. Inside our next Handlebars expression, we'll use an inverted block symbol and the @first data variable to determine if we should add a comma and space. Then close the inverted block. Next, we'll output the string, which we'll reference with this. Finally, close the each and end your statement. Now we'll use a few of our Handlebars dance steps by compiling the template and storing it in a compiled variable. And the last step is to console.log out the execution of our compiled function call, passing in data. This should output the rendered template to our console for us to see. Now, just save your file and switch over to the command line. To run this mini program, enter the command node node-test.js. And you should see the output of our template with all three places concatenated. Now you can say that you have used Handlebars in Node. Obviously, this is a contrived example, but you can use Handlebars with any web framework to do server-side rendering. And since Handlebars also works in the browser you can reuse templates between the two. If you're curious to find out more about using Handlebars with Node, check out my course Building Web Applications with hapi. We use the hapi web application framework in conjunction with Handlebars to render web pages on the server with Node. Take a look if it's something you're interested in.
Handlebars in the Wild
Handlebars has been in the wild for many years now and it has mutated and adapted into many different contexts. Besides vanilla Handlebars that we've been studying, there are a few other places you'll find it that I thought it might be fun to talk about. HTMLBars is an extension of Handlebars that emits DOM instead of a string. When rendering a template, Handlebars returns a string. And anytime we insert that into the DOM with the jQuery HTML function the browser converts that string into DOM elements. Unfortunately, that conversion ends up being a rendering bottleneck and hurts performance when rendering a lot of nodes. HTMLBars was developed specifically to avoid that rendering bottleneck. The other main difference that HTMLBars brings is that it is HTML aware. Handlebars isn't aware of the HTML structure of a template, it just looks at the expressions and ignores everything else. HTMLBars instead is aware of where an expression exists and the DOM nodes around it. At HTMLBars version 0.14, anything you can do in Handlebars version 3 you can do with HTMLBars. HTMLBars is most notable for being found to power Ember.js since version 1.10. Speaking of Ember, another place you'll find Handlebars prominently is in Ember.js. Ember is a full client-side framework, providing you with data modeling, application structure, and many more goodies. Ember and Handlebars have a long history since Yehuda Katz co-created both of them. Until version 1.10, Ember used Handlebars as its main rendering engine. At that time, HTMLBars was introduced, which acts as a wrapper around Handlebars. Key differences with Ember's use of Handlebars and HTMLBars is that many of Handlebars rough edges have been cleaned up. For instance, many Handlebars API functions are removed in place of Ember functions which use them. Also, the this keyword in helpers has been removed, further cleaning up scope and preventing mistakes. If you need your application to do more than what Handlebars can provide then take a look at Ember. Spacebars, I love the name, is the rendering engine in Meteor, an isometric JavaScript framework. It is heavily influenced by Handlebars, but is an independent implementation. Where Handlebars has many quirks and a deep API, Spacebars is more targeted and minimal. In addition, Spacebars is developed specifically for building templates for Meteor so there are plenty of idiosyncrasies. If you want to use a reactive version of Handlebars on the server side give Spacebars and Meteor a try.
Conclusion
It's been a long road taking our simple static application to the client-side rendering, precompiled beast application that it is now. Great job making it this far. Let's review what we covered in this module. First, we overviewed ways to get templates into our browsers. I suggested pre-compilation as the best way and introduced you to gulp, a build tool that makes it possible. We broke up our templates into their own files and then set up gulp for pre-compilation. Using Node, we rendered a quick template on our server and finally looked at where else Handlebars has been hiding. Thank you so much for taking this course. I really hope you learned something and are inspired to use Handlebars in your future projects. It really is an essential tool in any JavaScript developer's toolbelt. If you have any comments or feedback please don't hesitate to leave a comment in the course discussion or shoot me a tweet. It's been my pleasure to teach you all about Handlebars, and I'll see you next time.
Course author
Ryan Lewis
Ryan Lewis is a Software Engineer who specializes in ambitious single page web applications. He teaches Java and JavaScript to aspiring web developers and technology professionals. In his free...
Course info
LevelBeginner
Rating
(123)
My rating
Duration2h 19m
Released30 Sep 2015
Share course