Search code examples
javascripthtmlhandlebars.js

Handlebars Template Script in seperate file


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">?


Solution

  • 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.

    <script>
    // file extension doesn't matter, just make sure it's a plain text file
    const templateFilePath = '/js/templates/head-and-stuff.handlebar';
    
    fetch(templateFilePath)
      .then((response) => response.text()) // read the text from stream
      .then((templateString) => {
    
        // compile the template
        const compiledTemplate = Handlebars.compile(templateString);
    
        // add data to the template
        const renderedTemplate = compileTemplate({
            ...
        });
        
        // add the compiled template to the DOM
        document.querySelector('#some-elem').innerHTML = renderedTemplate;
      });
    </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.