Right now I have all my Handlebars templates in the same html file as my site. It would look somewhat like this:
var header_template = $("#header-template").html();
var content_template = $("#content-template").html();
var footer_template = $("#footer-template").html();
$(document).ready(function() {
// Footer
handlebars = Handlebars.compile(footer_template);
var content_rendered = handlebars({footer});
$('.footer-target').replaceWith(content_rendered);
// Header
handlebars = Handlebars.compile(header_template);
var content_rendered = handlebars({header});
$('.header-target').replaceWith(content_rendered);
// Content
handlebars = Handlebars.compile(content_template);
var content_rendered = handlebars();
$('.content-target').replaceWith(content_rendered);
});
<!-- ... head and stuff ... -->
<body>
<div class="wrapper">
<div class="header-target"></div>
<div class="content">
<div class="content-target"></div>
</div>
<div class="footer-target"></div>
</div>
</body>
<script id="footer-template" type="text/x-handlebars-template">
<div class="footer font-small d-flex justify-content-center">
<div class="text-center" style="min-width: 100%">
{{#each footer.content}}{{this}}{{/each}}
</div>
</div>
</script>
<script id="header-template" type="text/x-handlebars-template">
<div class="header">
<div class="headerImg"></div>
<ul class="nav">
{{#each header.items}}
<li class="nav-item">
<a class="nav-link">{{this}}</a>
</li>
{{/each}}
</ul>
</div>
</script>
<script id="content-template" type="text/x-handlebars-template">
<!-- content stuff -->
</script>
This works fine so far, but the more template scripts I add, and the bigger they get, the less readable the html file becomes.
Is there a way to store the content of the <script type="text/x-handlebars-template"></script>
tags in a seperate file and load them into the html, like for example with <script src="footer-template.htm">
?
2
Answers
It’s basically the same like in your first code block, just with an additional AJAX request to get the template.
So instead of
<script type="text/x-handlebars-template">
you’ll have to use a simple<script>
and fetch the file, then apply the template and append it to the element where you need it.I’ll do the example code with native fetch API, but you can use any AJAX library you want. (jQuery, Axios…)
Just make sure that
Handlebars
is loaded before the script.This is a simplified version of the fetch, you may want to add some checks to catch errors and edgecases depending on your project.
If you have more templates to load, you could wrap the fetch into your own function which accepts the template file path and the DOM element where it should be placed.
Thinking Architecture
For bigger projects, you may want to take a step back and think about your architecture. By loading content from external files, there are moments where the web page will render without your content, and then flash when the content is loaded, which might be a poorer user experience.
Generally, you may want to move all the templating server-side, or use some sort of builder that can combine templates from different sources into a built
index.html
file that has all of your templates (like in your original example).Doing this client side without dynamic data has code smell and probably could be done better.
That said, it is possible to load separate handlebars files client-side and render them.
Loading from non-JS script elements
You can specify attributes, like
src
, toscript
elements. For non-javascript types, it’ll get ignored by the parser, but you can manually use it later (for instance by usingfetch
).If your content only appears once, one approach could be to put the
<script>
tag where you want it to occur in the body, and replace it with the content later programmatically. It can look something like this, with external files forheader.hbs
,content.hbs
, andfooter.hbs
:Customizing per file
If you need to define additional attributes to a specific handlebars file (like specific data to use), you could use data attributes. For instance if your header and footer have to use different data to render, you could do something like:
And your data may look something like this:
And you’d change
handlebars(data)
tohandlebars(data[script.dataset.useDataName])
: