Desarrollo móvil multiplataforma
 

Tutorial de Backbone.js – IV. Vistas

Tutorial de Backbone.js – IV. Vistas

Introducción

Las vistas en Backbone son clases de control que nos ayudarán a representar nuestros modelos dentro de la interfaz de usuario de nuestra aplicación, detectando eventos de modificación para realizar las actualizaciones correspondientes.

Realmente las vistas no realizan un tratamiento directo sobre el HTML o CSS de tu aplicación, y Backbone espera que utilicemos algún sistema de templates que se encargarán de realizar dicho trabajo. Normalmente utilizaremos _.template de underscore.js o algún plugin de templates jQuery.

Creación de vistas

Como todo objeto Backbone que hayamos visto, lo primero que debemos hacer para crear una vista es definirla utilizando el método extend de Backbone.View:

FichaCliente = Backbone.View.extend({
    initialize: function(){ /* ... */},
    render: function(){ /* ... */}
});
var ficha = new FichaCliente();

Además de la función initialize que ya conocemos, también implementaremos otra función llamada render que se llamará cada vez que se necesite redibujar la vista.

La propiedad el

Cada instancia de una vista contendrá una propiedad llamada el, que será el objeto DOM que tendrá todo el contenido de la vista. Este elemento se crea automáticamente como un elemento div vacío, salvo que se indique lo contrario con las propiedades tagName y className:

FichaCliente = Backbone.View.extend({
    tagName: 'li',
    className: 'ficha'
});
alert( (new FichaCliente).el.className)); // 'hola'

Por defecto, dicho elemento se crea fuera de la estructura DOM del navegador, por lo que no será visible hasta que no lo insertemos en algún otro elemento existente en el documento:

$(document).ready(function(){
    Vista = Backbone.View.extend({
       render: function(){
           $(this.el).text('Hola Mundo');
           return this;
       }
    });
 
    var v = new Vista();
    $('body').append(v.render().el); //Insertamos el div dentro del body de la página
});

En este ejemplo hemos utilizado la función $.ready de jQuery para asegurarnos de que el código se ejecute cuando se haya cargado completamente el documento, cosa que debemos hacer siempre que queramos manipular el DOM. Nos hemos apoyado en jQuery como manipulador DOM ya que Backbone no realiza estas tareas, pero también podríamos haber utilizado Zepto.js.

Por otra parte, también podríamos enlazar la propiedad el con algún elemento existente. Esto lo podemos hacer en el momento de la definición de la vista si queremos que todas las instancias de dicha vista compartan el mismo el, o hacerlo en el momento de la creación de la instancia:

FichaCliente = Backbone.View.extend({
    el: $('.listaFichas')    // Todas las vistas FichaCliente compartirán el mismo el,
                             // salvo que se redefina al crear la instancia
});
var fichaActual = new FichaCliente({
    el: $('#fichaActual')  // Indicamos el elemento DOM de esta instancia en particular
});

También conviene indicar que si se utiliza jQuery o Zepto.js, cada instancia de vista tendrá una función local $ que permitirá realizar búsquedas locales dentro de la vista:

this.$('.nombreClase') == $('.nombreClase', this.el); // true

Dibujando vistas con plantillas

Como hemos dicho al principio, la función render será la encargada de dibujar nuestra vista, incluyendo dentro del elemento el de cada instancia todo el contenido HTML de la vista.

Aunque no es obligatorio, lo ideal es apoyarse en algún sistema de plantillas para mantener nuestro código javascript separado del contenido HTML. Backbone en sí mismo no ofrece ningún tipo de soporte para estas tareas, pero la librería underscore.js sí tiene un sistema básico de plantillas, y ya que Backbone depende de underscore.js podemos utilizar este sistema de plantillas para no tener que incluir ningún sistema externo.

Además de permitir separar nuestro HTML de nuestro código JavaScript, el uso de plantillas nos permitirá definir variables que podamos enlazar con los datos de instancias de modelos. Para que todo esto nos quede claro, veamos el siguiente ejemplo:

FichaCliente = Backbone.View.extend({
    template: _.template($('#ficha_template').html()),
    render: function(){
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    }
});
var cliente = new Cliente({nombre:'Alfonso', apellidos:'Marín Marín'});
var ficha = new FichaCliente({el:$('body'), model: cliente});
ficha.render();

En el ejemplo lo primero que hacemos es definir una plantilla identificada como ‘ficha_template’ donde se esperan dos variables a mostrar: nombre y apellidos. Posteriormente definimos nuestra vista donde guardamos la plantilla a utilizar en la propiedad template. Además implementamos el método render donde enlazaremos nuestra plantilla con la instancia de modelo que contendrá los datos, la cual se espera en la propiedad model y utilizando el método toJSON para obtener un objeto hash con los datos de la instancia.

Una vez definida la vista, creamos una instancia del modelo y otra instancia de la vista, asociándole la instancia de modelo en la propiedad model e indicando además que su elemento contenedor el será el body del documento. Por último llamamos a la función render para que cree todo el contenido de la vista bajo el contenedor body.

Delegado de eventos

Gracias al sistema de delegación de eventos de Backbone, una vista puede definir el comportamiento ante los eventos que ocurran dentro de los elementos existentes bajo el elemento contenedor el. Para ello se define un objeto hash llamado events con el siguiente formato en cada propiedad: {“event selector”: “callback”}. De esta forma indicaremos que para cada evento que ocurra bajo los elementos indicados por el selector se ejecutará la función callback.

FichaCliente = Backbone.View.extend({
    events:{
        "click .close": "cierraFicha",
        "click .sel" : "seleccionaFicha",
        "mouseover .title": "muestraToolTip"
    },
    seleccionaFicha: function(){
        this.model.set({'selected': true});
    }
    cierraFicha: function(){ /* ... */},
    muestraToolTip: function(){ /* ... */}
});

Si no se define ningún selector, el evento se asocia al propio elemento contenedor el. Una de las grandes ventajas de la delegación de eventos es que todas las funciones callback se invocan en el propio contexto de la vista, de forma que this apuntará a la propia instancia de la vista.

Enlazando vistas con modelos

Normalmente querremos sincronizar nuestras vistas con las instancias de modelo subyacentes. Para conseguir eso debemos enlazar los eventos de modificación de la instancia de modelo a nuestra vista, cosa que haremos normalmente dentro del método initialize:

FichaCliente = Backbone.View.extend({
    initialize: function(){
        this.model.bind('change', this.render, this);
        this.model.bind('destroy', this.remove, this);
    },
    render: function(){ /* ... */},
    remove: function(){ /* ... */}
});

Es importante cerciorarse de que enlazamos los eventos del modelo en el contexto apropiado. Como normalmente los métodos de vistas esperan ejecutarse en el contexto de la propia instancia de vista, en el método bind establecemos this como tercer parámetro, indicando así que queremos utilizar la propia instancia de vista como contexto.

Resumen

En este tema hemos analizado la creación de vistas Backbone y la importancia de la propiedad el. Hemos visto cómo hacer uso de plantillas para estructurar e independizar mejor nuestro código HTML, hemos analizado los eventos que intervienen en el sistema de vistas y por último hemos visto cómo enlazar nuestras vistas con los modelos de nuestra aplicación.

En el siguiente tema analizaremos otro componente de backbone: los Routers.

  1. José L February 10, 2012

    Hola Alfonso, gracias por tu tutorial, lo estoy siguiendo a ratos y se explican bien conceptos que en otros lugares están más farragosos. Se ve que lo has sufrido antes.

    Primero, comentarte que en la nota de cabecera de cada capítulo tienes mal el enlace al tutorial, te falta un “-de-” en la url. Sí que está bien en el menú superior.

    Después, en el capítulo de las vistas me ha surgido algo que no entiendo, y no consigo reproducir tu ejemplo, al explicar los templates dices: “En el ejemplo lo primero que hacemos es definir una plantilla identificada como ‘ficha_template’ donde se esperan dos variables a mostrar: nombre y apellidos. ”
    No consigo encontrar donde está eso hecho, y como es lógico, el código me da siempre un error de jquery. He intentado definir en el html un pero eso borra toda la página web creada.
    Te agradecería si pudieras explicarlo para los torpones de javascript.
    Por otro lado, estaría fenomenal si en algún sitio pusieras los archivos del código html y javascript que explicas. Hay veces que se dan por supuestas cosas que algunos no somos capaces de suponer, y nos perdemos.

    Un saludo y gracias

    • Alfonso Marín February 12, 2012

      Hola José:

      Gracias por avisarme del enlace, lo puse mal en el primero y ya sabes, el copy/paste haciendo de las suyas.

      Respecto a lo que me preguntas, es verdad que no he puesto por ningún lado la plantilla “ficha_template”. Cuando digo eso, me refiero a que en alguna parte de nuestra página, ya sea en la misma página o en un fichero de templates externo, hemos definido esto:

      <script type="text/template" id="ficha_template">
      <div class="fichaCliente">
      <div class="campo"><div class="nombreCampo">Nombre:</div><%=nombre%></div>

      <div class="campo"><div class="nombreCamo">Apellidos:</div><%=apellidos%></div>
      </div>
      </script>

      Como ves, es implemente un codigo HTML con unas cuantas variables por en medio. Tienes toda la razón en que a veces doy cosas por sabidas, y no debería ser así.

      Voy a ver si tengo un ratillo y junto todos los ejemplos de los tutoriales para colgar los archivos.

      Gracias por la recomendación.

      Saludos

  2. José L February 12, 2012

    Alfonso, gracias por el template . Lo he puesto en el html que carga el js y funciona bien.
    Si me permites, ya puestos, te recomiendo http://jsfiddle.net/ para colgar el código de los ejemplos. Es una forma muy cómoda de que cualquiera pueda luego jugar con él creando su propio “fiddle” a partir de lo que pongas.

    Saludos y gracias.

  3. Ale Prieto March 3, 2013

    ¡bárbaro!

    me perdí con lo del template también jaja, no sabía dónde estaba… ¡gracias!

  4. JosethGuerrero March 10, 2013

    Muchas gracias, sigo aprendiendo, lo estoy implementando, aunque la verdad me hubiese gustado aprender emberjs, pues parece ser mejor, sin embargo no me decidí por él por la falta de documentación en español, pero backbone cubre igual mis necesidades, igual soy novato. Gracias por tu dedicación!

  5. mael March 21, 2013

    Amigo te tengo una pregunta,como leen los buscadores (google) las plantillas de backbone??.Tengo pensado usar backbone para desarrollar mi propio CMS de manera que el cliente pueda administrar su sitio por medio de una pagina especial para esto,y que alterminar de administrarla se genere dinamicamente una copia para el lado cliente (usuarios) con extension html (puro,sin nada de variables javascript).Me podrias dar una idea de como lograr esto,mi intension es que existan dos lados:

    1.-lado del administrador:donde todos es dinamico por medio de ajax,backbone,plantillas
    (en este lado no me preocupa la indexacion)
    2.-Lado cliente:donde solo exista contenido html para indexarlo optimamente a los buscadores

    saludos

  6. Cesar February 18, 2014

    Hola,

    Estoy trabajando con en el tema y me gustaria ver un ejemplo de como borrar datoss un item por ejemplo,
    Gracias