lunes, 7 de mayo de 2012

Introducción a Knockout (I)

Desde hace tiempo cada vez programo más en cliente. Para esto jQuery nos ofrece una gran ayuda, sobre todo con su gran cantidad de selectores que nos permite realizar tareas comunes como mostrar u ocultar información o crear elementos html "al vuelo" de una manera fácil.

Pues bien, una de las cosas que más odio de jQuery es tener que recorrer un div (o elemento html al gusto) para extraer toda la información que tienen los inputs para montar un JSON, y éste enviarlo al servidor. De igual forma es tedioso tener que mapear a mano cada valor recibido de "nuestro servidor" en los diferentes elementos html que tengamos en nuestra página. Tengo hecho un pequeño framework que me ayuda en este tipo de tareas (marcando los inputs, checkboxs o radiobuttons en los que deseo insertar o extraer la información) pero nunca me ha terminado de convencer.

Para resolver todo esto he descubierto, gracias a la plantilla de ASP.NET MVC4, un script que se llama Knockout. Knockout nos ayuda a interactuar de una manera fácil con la interfaz mediante el patrón MVVM (poniendo cada cosa en su sitio).

Y como todo se entiende mejor con código vamos a poner un ejemplo.
Nombre: <input data-bind="value: Nombre" type="text" />
Primer apellido <input data-bind="value: PrimerApellido" type="text" />
function ViewModel() {
    var self = this;
    
    self.Nombre = "John";
    self.PrimerApellido= "Doe";
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Bien, ¿que hemos hecho en el ejemplo? Pues hemos vinculado (bindeado en ese idioma que tenemos los informáticos) a través del atributo data-bind la propiedad value del input (o sea, lo que se muestra) con el valor de Nombre o PrimerApellido que se definan en nuestro modelo (ViewModel).

Pero no solo estamos atados a datos estáticos sino que podemos quedarnos a la espera a que ese datos cambien para actualizar el valor en el otro lado. Veamos el siguiente ejemplo
Nombre: <input type="text" data-bind="value: Nombre" /><br />
Primer apellido <input type="text" data-bind="value: PrimerApellido" /><br />
Nombre: <span data-bind="text: Nombre"></span>
Primer apellido: <span data-bind="text: PrimerApellido"></span ><br />
function ViewModel() {
    var self = this;
    
    self.Nombre= ko.observable("John");
    self.PrimerApellido= ko.observable("Doe");
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Vemos que si cambiamos el valor de uno de los input, éste al perder el foco actualiza el valor del span, ya que ambos se han enlazado (incluido los cambios) al valor que tenga el modelo. Para esto hemos definido un observador que nos da knockout. Como vemos con poco código hemos vinculado la actualización de un campo con nuestro modelo (y viceversa). Lo cual es ideal, para el caso de recibir valores de nuestra API a través de llamadas ajax.

A veces nos puede venir bien combinar dos valores, y establecerlos en una propiedad, pero a su vez estar atentos a su cambios. Este ejemplo lo vemos con el siguiente código
Nombre: <input type="text" data-bind="value: Nombre" /><br />
Primer apellido <input type="text" data-bind="value: PrimerApellido" /><br />
Hola <span data-bind="text: Mensaje"></span ><br />
function ViewModel() {
    var self = this;
    
    self.Nombre= ko.observable("John");
    self.PrimerApellido= ko.observable("Doe");
    self.Mensaje= ko.computed(function() {
        return this.Nombre() + " " + this.PrimerApellido();    
    }, this); 
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Como vemos el uso de un "modelo" con estos observadores hacen que mejore la legibilidad del código que escribimos, aunque la potencia de Knockout no queda aquí, ya que también nos permite:
  • Engancharnos a eventos como el click o el checked
  • Establecer observadores sobre colecciones (útil para mantener una lista de los checks marcados para un filtrado).
  • Mostrar u ocultar información en base a criterios (por ejemplo una lista vacia) que podemos definir en nuestro modelo.
  • Iterar sobre colecciones para crear elementos en la UI.

No hay comentarios:

Publicar un comentario