Handlebars.js is a dream come true for anyone looking to simplify the process of generating dynamic HTML content with JavaScript. It’s built on top of Mustache, giving it more advanced features while keeping things simple and intuitive. It’s a favorite go-to for many developers and easily integrates into front-end frameworks. In this article, we’ll break down the basics, show off some examples, and demonstrate how to make the most out of Handlebars.js.
Handlebars.js is precisely the tool you need when your project involves a lot of dynamic content updates. Got a REST API sending over data or a user-triggered action that needs to reflect changes instantly in your view? Handlebars.js decouples your JavaScript and HTML, making everything streamlined and manageable. One of the key things to note is that it’s logic-less – it doesn’t directly support if-else or loops in templates. Instead, it uses built-in helpers to handle such logic – making your templates clean and simple.
Let’s get into how Handlebars.js expressions work. Think of a Handlebars template as regular HTML but with some magic words embedded between double curly braces {{ }}
. For example:
<script id="header" type="text/x-handlebars-template">
<h1>{{ firstName }} {{ lastName }}</h1>
</script>
To make this template come alive, you compile it and pass in some data:
var templateScript = $('#header').html();
var template = Handlebars.compile(templateScript);
var person = { firstName: "Betty", lastName: "White" };
$('header').append(template(person));
And voilà! Your data is there right in your HTML, just like that:
<header>
<h1>Betty White</h1>
</header>
Now, this is where it gets even cooler. The data object passed to Handlebars can include arrays, objects, strings, and numbers. Imagine you have an array of people that you want to display. Easy peasy with the {{#each}}
helper:
<script id="people-list" type="text/x-handlebars-template">
{{#each people}}
<li>{{ firstName }} {{ lastName }}</li>
{{/each}}
</script>
And on the JavaScript side:
var data = {
people: [
{ firstName: "Michael", lastName: "Jackson", age: 20 },
{ firstName: "Betty", lastName: "White", age: 150 }
]
};
var templateScript = $('#people-list').html();
var template = Handlebars.compile(templateScript);
$('body').append(template(data));
Suddenly, you have a dynamic list of people populating your page. Handlebars sure knows how to make things look effortless.
Let’s look at the Handlebars playbook step-by-step.
-
Define the Template:
<script id="person" type="text/x-handlebars-template"> <h1>{{ firstName }} {{ lastName }}</h1> </script>
-
Compile the Template:
var templateScript = $('#person').html(); var template = Handlebars.compile(templateScript);
-
Execute the Template with Data:
var person = { firstName: "Betty", lastName: "White" }; $('header').append(template(person));
Now, about safety and HTML escaping. Handlebars does a solid job of keeping your web app secure by automatically escaping values to prevent XSS (cross-site scripting) attacks. But on those rare occasions when you want to include raw HTML, just use the “triple-stash” {{{ }}}
notation:
<div>{{{ rawHTML }}}</div>
If you’re crafting a helper that produces HTML, mark it as safe using Handlebars.SafeString
:
Handlebars.registerHelper("bold", function(text) {
var result = "<b>" + Handlebars.escapeExpression(text) + "</b>";
return new Handlebars.SafeString(result);
});
Another power move is using partials in Handlebars, which let you reuse templates, cutting down on redundancy and making maintenance a breeze. Registering a partial involves the registerPartial
method:
Handlebars.registerPartial("person", "{{person.name}} is {{person.age}} years old.");
And then using it in a main template is simple:
<script id="main-template" type="text/x-handlebars-template">
{{> person person=person}}
</script>
Handlebars wouldn’t be as awesome without its built-in helpers. If you need conditional logic or iteration, it’s got you covered:
<script id="conditional-template" type="text/x-handlebars-template">
{{#if isAdmin}}
<p>Welcome, Admin!</p>
{{else}}
<p>Welcome, User!</p>
{{/if}}
</script>
Or for looping through items:
<script id="each-template" type="text/x-handlebars-template">
{{#each items}}
<li>{{ this }}</li>
{{/each}}
</script>
Loading templates is straightforward with script tags. Here’s a prime example:
<script id="template" type="text/x-handlebars-template">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</script>
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
<script>
var templateScript = $('#template').html();
var template = Handlebars.compile(templateScript);
var data = { title: "Handlebars.js", description: "A templating engine for JavaScript" };
$('body').append(template(data));
</script>
Time for a practical example – a dynamic task list:
HTML
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Task List</title>
<style>
body { font-family: 'Arial', sans-serif; margin: 20px; }
h1 { color: green; }
#taskInput { margin-bottom: 10px; }
ul { list-style-type: none; padding: 0; }
li { margin-bottom: 5px; }
li span { margin-right: 10px; }
button { cursor: pointer; }
</style>
</head>
<body>
<h1>Dynamic Task List</h1>
<input type="text" id="taskInput" placeholder="Add a new task">
<button onclick="addTask()">Add Task</button>
<ul id="taskList"></ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
<script id="template" type="text/x-handlebars-template">
{{#each tasks}}
<li>
<input type="checkbox" {{#if completed}}checked{{/if}} onclick="toggleTask('{{id}}')">
<span> {{title}} </span>
<button onclick="removeTask('{{id}}')"> Remove </button>
</li>
{{/each}}
</script>
<script src="script.js"></script>
</body>
</html>
JavaScript
let tasks = [
{ id: "1", title: "Python", completed: false },
{ id: "2", title: "ReactJS", completed: true },
];
const src = document.getElementById("template").innerHTML;
const template = Handlebars.compile(src);
function updateTaskList() {
const html = template({ tasks });
document.getElementById("taskList").innerHTML = html;
}
function addTask() {
const taskInput = document.getElementById("taskInput");
const newTask = { id: tasks.length + 1, title: taskInput.value, completed: false };
tasks.push(newTask);
taskInput.value = "";
updateTaskList();
}
function toggleTask(id) {
tasks.forEach(task => {
if (task.id === id) {
task.completed = !task.completed;
}
});
updateTaskList();
}
function removeTask(id) {
tasks = tasks.filter(task => task.id !== id);
updateTaskList();
}
updateTaskList();
This example gives you a fully dynamic task list where you can effortlessly add, toggle, and remove tasks.
In summary, Handlebars.js is your trusty sidekick for generating dynamic HTML. Its logic-less nature, built-in helpers, partials, and security measures make it a polished and reliable tool for any web developer. With the tips and examples provided, you’re ready to start harnessing the power of Handlebars.js in your projects, making your web development processes more efficient and your applications more interactive and engaging.