JsRender, JsViews como motor de templating para HTML5, jQuery y móviles

JavaScript templating en jQuery con JsRender y JsViews

Tal y como comentamos en un post anterior, el uso de un motor de templating en JavaScript, y más concretamente en jQuery, es una manera muy interesante de aislar la vista del modelo, y de poder generar posteriormente a partir de una plantilla el contenido a partir de los datos del modelo.

Si bien os hablábamos entonces de jQuery-tmpl como un motor válido para realizar estas tareas, dejábamos caer que este sistema ya no era el oficialmente “recomendado” por el equipo que hay detrás (en este caso y si no recuerdo mal jQuery UI), y que todo ese desarrollo se estaba migrando ahora a JsRender y JsView.

JsRender es un motor de templates basado completamente en Strings, sin dependencias del DOM o incluso de jQuery, pudiendo incluso correr en el servidor mediante node.js. JsRender es muy rápido, tanto que según su creador es aproximadamente 20 veces más veloz renderizando que su predecesor jQuery.tmpl…

Montado sobre JsRender, está JsViews, que básicamente amplía la funcionalidad de JsRender para pasar a un modelo de “vistas” que no son otra cosa que templates renderizados, permitiendo un anidamiento entre ellas, y por tanto una jeraraquía. Además JsViews, amplía la funcionalidad mediante data binding permitiendo que cambios en el modelo sean automáticamente adoptadas por las vistas dependientes… pero vamos a dejarnos de teoría y pasamos a un ejemplo sencillo…


Un ejemplo de uso de JsViews con data binding

Tenemos una pantalla de listado de contactos con una imagen, un nombre y un telefono, que se carga desde el servidor mediante JSON. Queremos que nuestra pantalla se alimente de dichos datos, pero en vez de generar el HTML desde el servidor, o en vez de parsear el JSON a “manubrio” en la respuesta de la petición AJAX, queremos ser elegantes y usar templates. Nos centraremos en la parte cliente.

Ficheros JavaScript Requeridos: jQuery, jsrender, jquery.views y jquery.observable





Para este ejemplo, necesitamos jQuery, necesitamos jsrender y jquery.views.js y para convertir un array en una especie de “datasource” de nuestra vista, necesitamos jquery.observable.js.

El Template de nuestra Demo




Es muy importante tener claro que este template ha de ir dentro del body de nuestro documento, nunca en el head, ya que no sería accesible, y que el uso de la etiqueta script hace que podamos validar correctamente el documento que lo contiene, además de dejar el contenido del template fuera del DOM, lo cual es muy importante para aislar el template como tal de las operaciones que podamos hacer posteriormente sobre el resultado del template (ya que sino sería un elemento más que podrían devolver nuestros selectores, por ejemplo).

El etiquetado HTML

    ¿Sencillo?… ¡Mucho!
    Este elemento HTML será el contenedor para nuestro template, es decir, el template se reproducirá en función de los datos del array de elementos tantas veces como sea necesario. De ahi que el template sean elementos “li”, ya que están pensados así porque su contenedor será un elemento “ul”, como tenemos aquí etiquetado. Evidentemente el etiquetado a reproducir en el contenedor y el template es el que deseemos obtener como resultado, totalmente libre.

    La magia

    function onDataLoaded(json)
    {
    	contacts = json;
    	$contactList.link(contacts, contactTemplate);
    }
    
    var contactTemplate = $('#contactTemplate').template();
    var $contactList = $('#contactList');
    var contacts;
    
    $.ajax({
    	url: "php/server.php",
    	cache: false,
    	dataType: 'json',
    	success: onDataLoaded
    });
    

    Como podéis ver, lanzamos la petición AJAX que nos dispara la función onDataLoaded, donde simplemente se accede al elemento CONTENEDOR mediante jQuery que queremos enlazar con la “fuente de datos”, y se le indica el template que empleará para mostrar esa fuente de datos en el método link. ¡Una línea!…Y listos… salvo que nos hayamos emocionado, como es el caso, y deseemos ver como efectivamente podemos cambiar el modelo y ver ese cambio reflejado de forma totalmente automática en la vista!

    Cambios en el modelo, reflejo automático en la vista

    function addContact() 
    {
    	var newContact = {
    	name: $('#name').val(),
    	phoneNumber: $('#phoneNumber').val(),
    	image: 'img/new_profile.jpg',
    	imageDescription: 'Un gran tipo dinámico'
    	};
    
    	$.observable(contacts).insert(contacts.length, newContact);
    }
    
    function removeContact(e) 
    {
    	var $target = $(e.target);
    	var index = $target.parent().prevUntil('#contactList').length;
    	
    	$.observable(contacts).remove(index, 1);
    }
    

    Además debemos añadir a la función onDataLoaded estas dos líneas al final:

    $('#addContact').on('click', addContact);
    $contactList.on('click', 'li>button', removeContact);
    

    Aqui lo que tenemos son 2 funciones que se emplean para añadir o quitar elementos de la lista. Para añadir, obviamente entendemos que existe un “button” con id “addContact” y un par de inputs con ids “name” y “phoneNumber” que hacen que el nuevo elemento que se añada tome esos valores. Mediante la implementación de observable que incluye el proyecto JsViews, hacemos un insert en el array de contactos que transmitirá el cambio a la vista.

    En el caso del borrado, para encontrar el índice del elemento a borrar del modelo, empleamos el método de jQuery prevUntil que nos sirve para tomar todos los “hermanos” anteriores a un elemento, hasta un selector dado. Lo que hacemos es acceder al li que contiene al botón pulsado, y contar la cantidad de hermanos que existen antes de él, lo que nos dá el índice de ese elemento en el array de datos. Ese valor ya lo podemos pasar al método remove con observable para que elimine el adecuado.

    Cuidado con los caracteres no estándar!

    
    

    Si el array de datos que actúa como modelo lo has incrustado en el código del fichero html, y usas caracteres latinos como acentos, eñes, etc. podrás comprobar que no se visualizan correctamente (no así los que se le añaden mediante observable… aunque tu fichero esté guardado correctamente en utf-8. Para solucionar este problema, has de meter este meta obligatoriamente en tu fichero:

    Os dejamos un enlace a la demo, y los ficheros para su descarga, donde tenéis comentado como se trabajaría con JsRender de manera similar, aunque sin el data-binding mediante el sistema “observable”.

    View Demo Source Code
    En definitiva, JsRender nos permite trabajar con plantillas de una manera más basica, aunque con un gran rendimiento, siendo el sustituto natural de jquery-tmpl, además de disponer de mecanismos de renderizado para codificación HTML o no como {{= }}, {{= !}}, condicionales para poder adaptar la plantilla en función de los contenidos de cada objeto a renderizar {{if}}, {{else}} e incluso de recorrido iterativo con {{each}}… y JsViews extiende aun más allá la funcionalidad permitiéndonos estructuras combinadas complejas, y vinculación de vistas a modelos que se actualizan de forma automatizada.

    Podéis encontrar unas buenas slides del creador en slideshare, y por supuesto más información en GitHub en ambos proyectos: JsRender + JsViews. También es altamente recomendable el analizar a fondo los buenos conjuntos de demos que hay disponibles para ambos proyectos (JsRender Demos y JsViews Demos).