Carga de plantillas para HandleBar.js desde ficheros externos

Posted by in Javascript y TypeScript, Programación

En la anterior entrada hablamos ampliamente de cómo utilizar Handlebars.js para utilizar plantillas HTML, que estaban incrustadas dentro del código HTML. Cómo ya os comenté, para un ejemplo o para pequeñas cosas, está muy bien, pero cuando vas a trabajar con aplicaciones más grandes, …. cómo que es mejor una reorganización del código, y por tanto, extraer esas plantillas para incluirlas como ficheros independientes.

Preparando las plantillas

En el directorio de trabajo, a los directorios clásicos css, y javascript, ahora crearemos uno nuevo llamado templates, que será donde guardaremos las plantillas. Concretamente, hemos extraido las plantillas del código (recuerda que en nuestro ejemplo de la entrada anterior, todo estaba en un solo fichero) y ahora tenemos dos ficheros .hbs llamados listado e info.

Organización proyecto Handlebars

Organización proyecto Handlebars

El código de listado.hbs es:


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

Cómo verás, es exáctamente lo mismo que había entre las etiquetas script.

Lo mismo que para 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>

Reescribiendo el fichero HTML

Ahora toca reestructurar el código HTML, que es exáctamente lo mismo que el anterior ejemplo, pero eliminado las plantillas (porque las hemos puesto en ficheros externos).


<!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>

Hasta aquí, no hay ninguna novedad, sólo hemos limpiado el código HTML para dejarlo más clarito. Sólo nos queda el código en Javascript (al igual que antes, yo lo he incluido al final del fichero, aunque también lo puedes poner en un fichero js y referenciarlo con script.

 Dos funciones Javascript para cargar las plantillas

Para la carga de plantillas desde ficheros externos, he visto varios ejemplo, aunque mi inspiración ha sido esta. Se trata de dos funciones: la primera para la descarga de la plantilla, y la segunda, la ejecución de la plantilla aplicándole una función.

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()}
    })
};

El gran truco de estas dos funciones reside en dataType: «html», indispensable para recuperar el contenido como HTML y poder así transferir la cadena de caracteres a Handlebars, en la función getTemplateAjax. La segunda tarea complicada es definir la función callback que se ejecutará en getTemplateAjax una vez recuperada la plantilla desde el fichero externo, y que es definida en renderHandlebarsTemplate.

Versión 3 del código Javascript de nuestro ejemplo sobre cervezas

Ya tenemos gran parte del trabajo, así que reorganizamos el código Javascript para el uso de estas funciones:

$(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;
                            }    
                        }
        });
    }
});

Cómo podrás comprobar, el resultado obtenido es exáctamente el mismo que el del ejercicio 2 ya visto en la entrada previa sobre Handlebars, aunque ahora tenemos una gran ventaja: hemos definido dos funciones que nos permiten tener nuestro código más organizado, lo que redundará en beneficio para un buen mantenimiento, y sobre todo, para hacer fácil lo que parecía complicado.

El código lo tienes en GitHub, por supuesto, pero ya te adelanto que hay pendiente una cuarta versión de este sencillo ejercicio, cuando hablemos de TypeScript.

Happy coding!