Advanced Templating Lab
Last updated
Last updated
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 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:
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:
First we grab the innerHTML
of our template. You can think of this as a String
. Next, we use Handlebars.compile
to create the templateFn
function using the innerHTML
of our template. It's important to note that Handlebars returns a function whose inputs are the "blanks" that will get filled in by the data passed into the function. Finally, we execute the templateFn
function with a context object, recipe
, to get rendered HTML. The "keys" in the context object will be filled in with the corresponding value for each call to the "key" inside the template string.
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.
Let's look at a quick example.
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.
You'll be building out 3 screens: New Recipe, Show Recipe, Edit Recipe. When you're done, a user should be able to:
Visit the page and see a form to create a new recipe, fill it out and submit it (New Recipe)
See the recipe details and a link to edit the recipe (Show Recipe)
Click the link to Edit the recipe and see the form rendered with pre-filled values (Edit Recipe)
Update the values in the edit form and submit it to change the recipe (Edit Recipe)
View the updated recipe details (Show Recipe)
For simplicity's sake, only render one of these screens at a time. If we wanted to send AJAX requests to different endpoints depending on whether we were editing or creating a new recipe, we could pass a submitFunction as part of our context for the templateFunction and pass a different function for each screen. But, since we don't have a back end here, we can use the same form template and the same function to handle the submission.
Note: The provided index.js
includes a function called init
that will be called when the page loads. Put any Handlebars registration code (think helpers & partials) and page initialization code you need inside this function or your tests will not function correctly. If you're running this lab using node 10+, you may not see test errors. Any node version from 6 through 9 should show you errors when you first run the tests.
Create a template with an id
of recipe-template
. This template should contain the recipe name
inside of a header tag with an id of recipeName
and an "Edit Recipe" link that calls the displayEditForm()
function on click. This template will then render the recipeDetailsPartial
you will build in the following step. Later, you'll render this template with the recipe data when the user submits the form.
On click of your "Edit Recipe" link, call a displayEditForm()
function that renders a template called recipe-form-template
. Allow your recipe to be edited using this form, and re-render the recipe template with the updated information. Hint How can you pre-fill the edit form with the correct values? Think about what information you have access to when a user clicks on the "Edit Recipe" link.
A is just a template that you can render inside of another template using the {{> partialName }}
partial call syntax after registering it with Handlebars.registerPartial
.
Create a form template with an id
of recipe-form-template
that will be used to enter new recipes. Configure handlebars to display this template within the main
tag (You'll need to do this within the init()
function for the tests to work properly). After doing this, your second test will be passing and you'll get meaningful errors on your first. Give the form an id of recipe-form
and have it submit with a handleSubmit()
function. Provide inputs for recipe name
, description
, and at least five ingredients
. Hint: Get comfy collecting values with getElementsByName()
. Also, make sure you give your name and description inputs a matching id (#name
& #description
). also might be useful here.
Register a partial called recipeDetailsPartial
for the description
and ingredients
of the recipe. Create a template with an id
of recipe-details-partial
to hold the markup. Make sure the description is rendered inside of a container with an id of recipeDescription
. Use the to display the collection of ingredients
. Within the loop, you'll want to invoke the displayIngredient
helper you'll define in the next step. Hint Think about where partials should be registered. For these tests, you can invoke the before defining it.
Define a custom helper called displayIngredient
to display each ingredient within the each
block. Each ingredient should be inside of an li
with a name attribute equal to ingredients
. Hint Check out the docs on . Also, think about where helpers should be registered.
Build out the handleSubmit()
function so that submitting the initial new recipe form will use the recipe-template
to display the recipe, all of its details, and the "Edit Recipe" link. Hint Don't forget that submitting a form will trigger a page refresh. In order to display the recipe, we'll need to hook into that event.
Clone: