Skip to content

Template Reuse

Overview

Compare index.hbs and courses.hbs; you will notice a fair deal of duplicated HTML statements. As a principle, code duplication is something we want to avoid. So let's take a look at some best practices that will avoid duplication in your template files.

Template inclusion

Handlebars, as well as most other templating languages, offer a way to reuse templates. This usually comes under the name of template reuse, or template inheritance, or template inclusion. It means the ability to embed part of a template into another one.

Make a new template file resources/templates/base.hbs and copy the content of index.hbs into it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CourseReVU App</title>
</head>
<body>
    <h1>Welcome to CourseReVU App</h1>
    <p>View <a href="courses">courses</a></p>
</body>
</html>

Notice that everything from the first line, until the opening of <body> is the same in courses.hbs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CourseReVU App</title>
</head>
<body>

We will use the #block construct in handlebars to define (and later reuse) a header block:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{{#block "header" }}
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>CourseReVU App</title>
    </head>
    <body>
{{/block }}

Moreover, the last two closing HTML tags are also common between index.hbs and courses.hbs (and likely in any other template file that we may create); let's define a footer block as follows:

1
2
3
4
{{#block "footer" }}
    </body>
    </html>
{{/block }}

What changes from index.hbs to courses.hbs is what comes inside the body (<body></body>); let's call that the content block:

1
2
{{#block "content" }}
{{/block }}

Note that I've left this block with no content!


At this point, the base.hbs must look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{{#block "header" }}
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>CourseReVU App</title>
    </head>
    <body>
{{/block }}

{{#block "content" }}
{{/block }}

{{#block "footer" }}
    </body>
    </html>
{{/block }}

index.hbs

Let's update index.hbs to reuse the base template:

1
2
3
4
5
6
{{#partial "content" }}
    <h1>Welcome to CourseReVU App</h1>
    <p>View <a href="courses">courses</a></p>
{{/partial }}

{{> base.hbs }}

The {{> base.hbs}} allows reusing the base template (kind of like using extends keyword in Java). Moreover, the #partial constructs allows to add to the content block which is inherited from the base template (kind of like @Overrride in Java).

courses.hbs

Let's update the courses.hbs to reuse the base template:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{{#partial "content" }}
    <h1>Courses</h1>

    <ul>
        {{#each courseList }}
            <li>{{ name }} at {{ url }}</li>
        {{/each }}
    </ul>

    <form action="/courses" method="post">
        <input type="text" placeholder="course name" name="coursename"/>
        <input type="text" placeholder="course url" name="courseurl"/>
        <button>Submit</button>
    </form>
{{/partial }}

{{> base.hbs}}

Rerun the WebServer and make sure our refactoring has not introduced any error; everything must work as before!