Las aplicaciones web actuales, en las que cada vez cargamos más y más javascript, contar con una librería como Backbone.js puede ahorrarnos más de un quebradero de cabeza ayudándonos a mantener un código ordenado y bien estructurado, evitando líneas y líneas de javascript, selectores y llamadas a funciones aquí y allá. Backbone.js facilita estructurar las aplicaciones web basándose en el paradigma de programación MVC, modelo, vista, controlador. Para aplicaciones enriquecidas del lado del cliente, un enfoque estructurado como el que ofrece este framework, es muy útil y beneficioso.
Modelo
Con Backbone.js, los datos se representan como modelos que pueden ser creados, validados, destruidos o almacenados en el servidor. Un modelo nos permite crear una estructura de información que define una entidad, de la siguiente manera:
var Persona = Backbone.Model.extend({
defaults: {
nombre: 'Nombre por defecto',
edad: 31
},
initialize: function() {
...
},
});
De esta forma, estamos definiendo el modelo Persona, con los atributos nombre y edad. El método initialize es el constructor que se lanza cuando se instancia un objeto de la clase Persona. Para crear una instancia de este modelo, haremos lo siguiente:
var pers = new Persona({ nombre: "Fulano de Tal", edad: 23 });
Leer y escribir los atributos se realiza por medio de los métodos get y set:
var nom = pers.get(‘nombre’);
pers.set({ edad: 32 });
En este punto, si queremos guardar el modelo en la base de datos en el estado en el que se encuentre, utilizaremos el método save, que enviará una llamada de tipo POST al servidor, a la dirección que se encarga de gestionar dicho modelo, o de tipo PUT, si el modelo ya existe.
pers.save();
Colecciones
Un conjunto de instancias de modelos, es en Backbone.js, una colección. Buscando un símil con bases de datos, podríamos decir que una colección es el resultado de una consulta SQL que devuelve un conjunto de registros.
Podemos crear una colección de la siguiente manera:
PersonasColletion = Backbone.Collection.extend({
model: Persona,
});
De esta forma estamos definiendo una colección de personas. Ahora podríamos, por ejemplo, incluir un método a la colección que devuelva aquellas personas menores de 18 años:
PersonasColletion = Backbone.Collection.extend({
model: Persona,
menoresEdad: funcion() {
return this.filter(function(pers) {
return pers.get('edad') < 18;
});
}
});
Además, las colecciones soportan las típicas operaciones de creación, lectura, actualización o borrado de elementos:
// crear (add)
var personas = new PersonasCollection;
personas.add([
{ name: 'Fulano de Tal', edad: 18 },
{ name: 'Mengano de Cual', edad: 26 }
]);
// leer
var fernando = editores.get(1);
// actuallizar
editores.at(0).set({posts: ['/un-post/super-chulo']})
// borrar
editores.remove(fernando);
Vistas
Las vistas en Backbone.js pueden resultar un poco confusas, ya que se asemejan más a un controlador que a una vista. Las vistas son clases que se encargan de representar los modelos dentro de nuestra aplicación y de escuchar los eventos lanzados por los modelos y las colecciones.
Esta es la estructura típica de una vista:
var PersonaView = Backbone.View.extend({
tagName: "div",
className: "persona",
initialize: function() {
this.model.on('change', this.render, this);
},
render: function() {
this.el.innerHTML = this.model.get('nombre');
},
events: {
'click .delete': 'deleteAction'
},
deleteAction: function(){
this.model.destroy();
return false;
}
});
var persView = new PersonaView({ model: persona, id: 'persona_' + persona.id });
Se define la vista PersonaView, con los atributos tagName y className en los que se indica el elemento raíz que generará la vista, en nuestro caso <div class=”persona”>, con el método constructor que ya conocemos, initialize.
El método render se llamará cada vez que se redibuje la vista, es quien se encarga de redibujarla cada vez que haya un cambio en el modelo.
El atributo el que se usa en el método render hace referencia al objeto DOM que tiene todo el contenido de la vista, es decir, el elemento html sobre el que actúa la vista, en nuestro ejemplo, representa a <div class=”persona”>.
Podemos definir en la vista el comportamiento frente a eventos que se produzcan en los elementos que contiene nuestro elemento el, del que hablamos anteriormente. Para ello, definimos un evento junto el callback con el formato: { 'evento selector': 'callback' }, en nuestro ejemplo: { ‘click .delete': 'deleteAction' }, indocando que para cada evento click que se produzca sobre los elementos con class=”delete”, se ejecuta la función deleteAction.
Routing
Por último, vamos a ver cómo enrutar las URLs de nuestros desarrollos a través del método extend del objeto Backbone.Router. Las rutas contendrán al menos una ruta y una función con la que mapearla, y se interpretan en la URL tras el símbolo ‘#’ (https://vabadus.es/#/personas).
var App = Backbone.Router.extend({
routes: {
"!/": "root",
"!/personas": "personas"
},
root: function() {
…
},
personas: function() {
…
}
});
En algunos casos, nos interesará también definir un enrutado dinámico, lo que resulta muy útil y muy fácil de implementar (https://vabadus.es/#/personas/53):
var AppRoutes = Backbone.Router.extend({
routes: {
"/posts/:id": "getPost",
…
},
getPost: function(id) {
…
},
…
});
Y hasta aquí este acercamiento a las características generales de backbone.js, en el que hemos visto cómo implementar MVC en el lado del cliente, estructurando nuestro código Javascript de una forma eficiente. En artículos posteriores iremos profundizando más en esta magnífica librería.