Loading templates from external files to use with Handlebars.js

Posted by in Javascript and TypeScript, Programming

In the previous entrance I started to write about how to use Handlebars.js for creating HTML templates, but they were embedded in the HTML code. This type of coding can be useful for a small example or for small things, but when you have to deal with large apps, it is recommended to use a different approach, reorganize your code and work with external files. That will be better!!

Preparing the templates

Under the working directory, I have created the classic directories css, and javascript, but now, I have created a new one called templates, where all out templates will be stored. Next step is do move the templates from the HTML to a external files (copy the HTML code as it was in version 2), and now I have two .hbs files called listado and info.

Organización proyecto Handlebars

Files of project Handlebars

The code of listado.hbs is:


<ul id="listado" class="list-group">
<li class="list-group-item list-group-item-info">
<h3 class="list-group-item-header"&gt;Cervezas&lt;/h3>
</li>
{{# each Beers}}
<li class="list-group-item"&gt;&lt;a&gt;{{Name}}&lt;/a&gt;&lt;/li>
{{/each}}
</ul>

As you canv erify, it is exactly the same code as it was in the script tags.

The code for info.hbs:


<div class="container">
<h1>{{Name}}</h1>
<div class="col-md-12">Brewery: <span class="label label-success">{{Brewery}}</span></div>
<div class="col-md-12">Estilo: <span class="label label-info">{{Style}}</span>- Graduacion: <span class="label label-danger">{{Abv}}</span></div>
</div>

Rewritting the HTML file

Now it is turn to rewrite the HTML code. It is exactly the same but removing the handlebars templates under the head section (now in external files).


<!DOCTYPE html>
<html lang="es">
<head>
	<meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="description" content="">

	<title>Manejando datos - HandleBarsJS templates example</title>

	<link href="css/bootstrap.min.css" rel="stylesheet" />

	<script src="js/handlebars-v3.0.3.js"></script>
	<script src="js/jquery-1.11.1.min.js"></script>
	<script src="js/bootstrap.min.js"></script>
</head>

<body>
	<div class="container jumbotron">
		<h1 class="text-center">MD y Handlebars con plantillas externas</h1>
	</div>
	
	<div class="container">
		<div class="col-md-3">
			<button id="carga" class="btn btn-success">Cargar datos</button>
		</div>
		<div class="col-md-3" id="content">Aqui va
		</div>
		<div class="col-md-3" id="masdatos">
			<strong>Sin selecci&oacute;n ...</strong><br/>
		</div>
	</div>
</body>
</html>

Until here, no noews. Just the HTML code have been cleaned, and next step is to code the Javascript part (as before, I included in the HTML file, but you can write it on a external js file and reference to it in the HTML file).

Two Javascript functions to load external templates

For loading templates from external files, I have seen several examples, but the one that inspired my has been this. I have build two functions: the first one is for downloading the tempalte, and the second one, is for building the template and apply a callback function.

function getTemplateAjax(path, callback) {
    var source, template;
    $.ajax({
        url: path,
        dataType: "html",
        success: function (data) {
            source = data;
            console.log('gettemplate');
            template = Handlebars.compile(source);
            if (callback) callback(template);
        }
    });
}

function renderHandlebarsTemplate(withTemplate,inElement,withData, callback){
    getTemplateAjax(withTemplate, function(template) {
        var targetDiv = (typeof inElement == 'string') ? $(inElement) : inElement ;
        targetDiv.html(template(withData));
        if (callback) { callback()}
    })
};

The key of this two functions is in the line dataType: “html”, that makes possible to retrieve the HTML code as a string, so you can transfer ir to Handlebars, in getTemplateAjax. function. The second tricky part is to define the callback function that will be executed in getTemplateAjax once the templates is loaded successfully, from a external file, and it is defined in renderHandlebarsTemplate function.

Versión 3 of the Javascript code beer example

Almost all work is done, so, let’s reorganize our code in order to use the functions I have created:

$(function() {
function getTemplateAjax(path, callback) {
    var source, template;
    $.ajax({
        url: path,
        dataType: "html",
        success: function (data) {
            source = data;
            template = Handlebars.compile(source);
            if (callback) callback(template);
        }
    });
}

function renderHandlebarsTemplate(withTemplate,inElement,withData, callback){
    getTemplateAjax(withTemplate, function(template) {
        var targetDiv = (typeof inElement == 'string') ? $(inElement) : inElement ;
        targetDiv.html(template(withData));
        if (callback) { callback()}
    })
};
    
    var ctx = {};
    var masdatos = $('#masdatos');
    
    $('#carga').on('click', function (e) {
        $.getJSON( 'beers.json',  { format: "json"}    )
        .done(
            function (data) {
                ctx.Beers = data;
                var destino = $("#content");
                renderHandlebarsTemplate('templates/listado.hbs', destino, ctx, refresca)
            }
        );
    });
    var refresca = function  () {
        $('#listado').find('li').on('click', function (e) {
                    $this = $(this);
                    var seleccion = $this.text();
                    var beer; var nombre = '';
                    for (index = 0; index < ctx.Beers.length; ++index)
                        { beer = ctx.Beers[index];
                        if (beer.Name == seleccion) {
                                renderHandlebarsTemplate('templates/info.hbs', masdatos, beer);
                                break;
                            }    
                        }
        });
    }
});

As you can see, the result of the new code is as expected, the same as version 2, although with one big advantage: you have defined two functions that allow you to have your files with a better organization, making more easy to maintain the project and making easy what it seems so complicated!

The code is available on GitHub, of course, but I want to warn you that there will be a version 4 of this exercise, after wa’ll talk about TypeScript.

Happy coding!