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!