- Practice using Handlebars templates
- Practice defining Handlebars helpers
- Practice using Handlebars partials
In this lab we're going to build a simple recipe application using Handlebars templates. Follow the instructions below, and don't forget to run test and try out your app to make sure everything works!
You'll be using templates, creating custom helpers, and using partials. Help can be found at the Handlebars website, and we'll briefly review the basics below.
We can construct templates within script tags using the {{}}
delimiters to mark data values, like this:
<script id="my-template" type="text/x-handlebars-template">
<div id="recipe">
<p>{{description}}</p>
<ul>
{{#each ingredients}}
<li>{{name}}</li>
{{/each}}
</ul>
</div>
</script>
Keep in mind that the placeholder values within the double curly braces must match the names of attributes on the object that you pass as context to the template.
We can also use the each
helper on a collection, in this case the ingredients
property of the current recipe, to render a part of a template multiple times.
To render this template, our JavaScript code would look like this:
var recipe = {
description: 'yummy chicken noodle soup',
ingredients: [
{quantity: "1 cup", name: 'chicken'},
{quantity: "3 nanoliters", name: 'stock'},
{quantity: "12", name: 'noodles'}
]
}
var template = Handlebars.compile(document.getElementById("my-template").innerHTML);
var html = template(recipe);
First we use Handlebars.compile
to create the template
function from the innerHTML
of our template, then we execute the template
function with a context object, recipe
, to get rendered HTML.
Handlebars also has the concept of a partial, or a bit of template that you can use to compose larger templates. Partials are useful when you have a chunk of markup that you want to reuse in more than one place.
A Handlebars partial is just a template that you can render inside of another template using the {{> partialName }}
partial call syntax after registering it with Handlebars.registerPartial
.
Let's look at a quick example.
<script id="main-template" type="text/x-handlebars-template">
{{> namePartial }}
</script>
<script id="partial-template" type="text/x-handlebars-template">
<div>{{ name }}</div>
</script>
Handlebars.registerPartial('namePartial', document.getElementById("partial-template").innerHTML)
function renderMain() {
var template = Handlebars.compile(document.getElementById("main-template").innerHTML);
var html = template({name: 'Gordon Ramsay'});
}
By default, the partial will receive the same context object as the template that calls it, so our partial has the same access to name
as the main template does.
- Create a form template with an
id
ofrecipe-form-template
that will be used to enter new recipes. Make the form submit with acreateRecipe()
function. Provide inputs for recipename
,description
, and at least fiveingredients
. Hint: Get comfy collecting values withgetElementsByName()
. - Create a template with an
id
ofrecipe-template
. This template should contain the recipename
and an "Edit Recipe" link, and render therecipeDetailsPartial
in step 3. Render this template with the recipe data when the user submits the form. - Register a partial called
recipeDetailsPartial
for thedescription
andingredients
of the recipe. Create a template with anid
ofrecipe-details-partial
to hold the markup. Use theeach
helper to display the collection ofingredients
. - Use a custom helper called
displayIngredient
to display each ingredient within theeach
block. - On click of your "Edit Recipe" link, call a
displayEditForm()
function that renders a template calledrecipe-form-template
. Allow your recipe to be edited using this form, and re-render the recipe template with the updated information using aupdateRecipe()
function on form submit. - Refactor your forms so that
recipe-form
and the edit form template are both constructed with the samerecipe-form-template
. The template should render with the recipe data for edit, and with empty values for a new recipe. Hint: Don't forget you can pass any object with any properties as the context for your templates, including, for instance, values foronsubmit
.
Note: The provided index.js
includes a function called init
that will be called when the page loads. Put any Handlebars registration code and page initialization code you need inside this function or your tests will not function correctly.