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!