Seguimos aprendiendo Javascript, y hoy toca una librería mítica (sí, pongo mítica porque lleva mucho tiempo siendo referencia) a pesar de que he comenzado a usarla hace muy poco (bueno, cuando me he metido de llevo a trabajar con Javascript y a confirmar mi odio más profundo a este lenguaje). Se trata de Handlebars.js:
Handlebars es un libreria muy potente que facilita el uso de plantillas, compatibles con Mustache, para facilitar la organización de código (e incluso la reutilización)
Usando plantillas
Las plantillas permiten predefinir cómo se presentará la información, de forma que se compila para presentar el resultado con los datos que se le envían.
Dentro del código HTML, se usan las marcas script:
<script type=”text/x-handlebars-template” id=”template-name”></script>
El uso de las plantillas se hace desde Javascript, y es muy importante identificar el tipo, y por supuesto, asignarle un nombre (yo he puesto template-name) para poder recuperarla.
Para tener más conocimiento de cómo funcionan las plantillas, lo mejor es pasarse por tryhandlebarsjs.com para verlas en acción, y así poder ver las distintas y variadas opciones que tienes. Yo no quiero aquí enseñarte a diseñar plantillas, sino a cómo utilizarlas desde Javascript (aunque me estoy pasando a TypeScript).
Un primer ejemplo
Para ver en funcionamiento Handlebars.js, vamos a realizar un pequeño ejercicio que iremos complicando, según vayamos consiguiendo objetivos. El primero es cargar unos datos en formato JSON y mostrarlos, cuando se pulse un botón de carga de datos. Para poner el ejemplo más bonito, utilizaré Bootstrap, mientras que necesitaré las librerías jQuery, bootstrap y por supuesto, handlebars (yo he utilizado la versión 3.0.3).
El archivo JSON es este:
[
{
“Name”: “Estrella”,
“Brewery”: “Damm”,
“Style”: “Euro Lager”,
“Abv”: “5.4”,
“Ibu”: “25”,
“Favorite”: false
},
….
]
Una vez tengo todos los ingredientes, preparamos el código HTML5 de la plantilla que usaremos con Handlebars:
<script type="text/x-handlebars-template" id="template-listado"> <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"><a>{{Name}}</a></li> {{/each}} </ul> </script>
Básicamente, siguiendo las instrucciones de uso de Handlebars, he puesto #each para que repita un bucle, y que ponga el nombre de cada cerveza.
Ahora, el código HTML completo:
<!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>Beer List, by ManejandoDatos.es</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> <script type="text/x-handlebars-template" id="template-listado"> <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"><a>{{Name}}</a></li> {{/each}} </ul> </script> </head> <body> <div class="jumbotron"> <h1 class="text-center">MD y Handlebars</h1> </div> <div class="container"> <div class="col-md-6"> <button id="carga" class="btn btn-success">Cargar datos JSON</button> </div> <div class="col-md-6" id="content"> </div> </div> </body> </html>
Sin embargo, aun falta la parte que hace el trabajo y que es el código Javascript, que incorporaremos bien en el mismo fichero al final, o en un fichero independiente .js agregando la dependenciaen el código HTML (yo, para este ejemplo, lo he incluido también en el mismo fichero todo).
El código Javascript para utilizar handlebars.js
El código es el siguiente, y que a continuación comentaré paso a paso:
$(function() { var stemplate = $("#template-listado").html(); var tmpl = Handlebars.compile(stemplate); var ctx = {}; $('#carga').on('click', function (e) { $.getJSON( 'beers.json', { format: "json"} ) .done( function (data) { // console.log(data); ctx.Beers = data; var html = tmpl(ctx); $("#content").html(html).show(); } ); }); });
Primero, recuperamos la plantilla que arriba llamamos template-listado, y la incorporamos a una variable. El segundo paso es compilar dicha plantilla según requiere Handlebars.js. Ahora, sólo queda pulsar el botón para que poner el mecanismo en marcha (he forzado poner un botón para que se identifique claramente dónde se desarrolla la acción, y que sea de mejor comprensión para el lector).
Al pulsar el botón, cargamos la cadena JSON con los datos, y los transferimos a la variable ctx. El penúltimo paso es crear la variable html donde utilizamos la plantilla compilada y le transferimos los datos recibidos. Por último, cargamos el resultado en el DIV #content, y lo mostramos.
Mostrando más datos de una cerveza
Aunque hemos conseguido el objetivo inicial propuesto, que era mostrar datos recibidos como JSON y generar el HTML utilizando una plantilla, todo procesado gracias a Handlbars.js, aun nos queda más información por mostrar, que es la información indivisualizada para cada cerveza. Por tanto, preparamos una segunda plantilla, que irá en el head:
<script type="text/x-handlebars-template" id="template-dato"> <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> - Graduación: <span class="label label-danger">{{Abv}}</span></div> </div> </script>
Y toca actuar de nuevo en el código Javascript, de forma que cuando se haga clic en una cerveza, se muestre la información.
$(function() { var stemplate = $("#template-listado").html(); var tmpl = Handlebars.compile(stemplate); var sdato = $("#template-dato").html(); var tmpldato = Handlebars.compile(sdato); var ctx = {}; var masdatos = $('#masdatos'); $('#carga').on('click', function (e) { $.getJSON( 'beers.json', { format: "json"} ) .done( function (data) { console.log(data); ctx.Beers = data; var html = tmpl(ctx); $("#content").html(html).show(); 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) { var html = tmpldato(beer); masdatos.html(html) break; } } }); } });
La explicación del código consiste en crear una función que permita actuar una vez cargada la primera información, y así, al hacer clic se muestre más contenido usando la segunda plantilla. La plantilla con la información individualizada se ha cargado igual que la del listado (su nombre es template-dato), a la espera de ser usada cuando corresponda con la información suministrada. Para seleccionar el registro corecto, lo hacemos en un bucle for hasta dar con la cerveza seleccionada. Una vez que la tenemos, aplicamos el registro a la plantilla y lo mostramos en el DIV correspondiente.
Esto de las plantillas está muy bien, pero ….
Pero es un poco guarreo mezclar las plantillas Handlebars dentro del HTML, que se escriben antes, se utilizan después, …. y para ser un ejemplo, vale, o para pequeñas cosas, pero ¿y cuando es una gran aplicación? Pues también hay solución, y te desvelo en la siguiente entrada!
Por cierto, el código lo tienes en GitHub.
Happy coding!