Hero

Routing y Controlling con MarionetteJS

Mayo 05, 2014

enzo
BackboneJS
JavaScript
MarionetteJS
jQuery

Anteriormente les había compartido algo de BackboneJS en los videos Integración Backbone.js con Drupal parte #1 y #2.

Hoy quiero compartirles sobre MarionetteJS que es un capa que se coloca sobre BackboneJS para poder crear aplicaciones escalables y profesionales.

Algunas de las características de MarionetteJS son

  • Escalable: Las aplicaciones están construidas en módulos, y con una arquitectura orientada a eventos.
  • Fácilmente modificables: Permite que funcione con las necesidades específicas de su aplicación
  • Reducir el trabajo de definir las vistas, con vistas especializadas.
  • Construye una arquitectura modular de la aplicación y los módulos que se adhieren a ella.
  • Componer visuales de la aplicación en tiempo de ejecución, con la Regions y Layouts
  • Vistas y diseños anidados dentro de los Regions
  • Incorporado gestión de memoria y matanza de zombie.
  • Arquitectura orientada a eventos con Backbone.Wreqr.EventAggregator
  • Flexible, arquitectura “on demand” que le permite seleccionar y elegir lo que usted necesita

Tomando en cuenta los conceptos explicados en los videos mencionados anteriormente nos enfocaremos en los conceptos de MarionetteJS.

En nuestro ejemplo tomaremos la estructura de librerías y dependencias explicada en la entrada de blog Qué es y como funciona RequireJS requeridas para crear una aplicación con MarionetteJS.

  1. Modulo de Router.

MarionetteJS implementa el objeto Marionette.AppRouter que permite definir las rutas a las que responderá nuestra aplicación. Usando RequireJS podemos crear un modulo que defina un objeto para nuestras rutas, además nos permite crear varios objetos de Route que podrán ser instanciados por distintas aplicaciones a conveniencia.

En nuestra aplicación creamos una carpeta modules en donde vivirán nuestros módulos, veamos una definición de ejemplo de un Route.

define(["marionette"], function (Marionette) {
  var Router = Marionette.AppRouter.extend({
    appRoutes: {
      "": "home",
    },
    /* standard routes can be mixed with appRoutes/Controllers above */
    routes : {
      "hello/:username": "helloBuddy"
    },
    helloBuddy : function (buddy) {
      // Without controller the routing functions live in Router object
      alert("Hello " + buddy);
    }
  });

  return Router;
});

Como vemos es una definición anónima que retorna un objeto Router, que luego sera cargada por nuestra aplicación.

Nuestro modulo carga la dependencia Marionette para poder hacer uso del objeto Marionette.AppRouter, veamos un poco sus propiedades.

AppRoutes: Propiedad que permite la definición de routes con la convención URL : Nombre Método , el método debe ser definido en el modulo Controller que sea asociada al Route dentro de la aplicación. Esta opción permite que las funciones de respuesta cambien radicalmente, dependiendo del controller que se asocie al Route.

routes: Propiedad que permite definir routes, pero se diferencia del anterior que los métodos estarán definidos dentro del objeto Router. Esta opción garantiza que cierta(s) rutas tenga un comportamiento especifico deseado.

Ambas propiedades se pueden usar en una misma definición sin problema, pero las rutas no se deben repetir.

Cuando se inicia la aplicación el Router dedicar donde están los métodos que se ejecutaran en respuesta a una ruta visitada por un usuario.

En la definición del Route vemos el uso de rutas con parámetros dinámicos. en la ruta hello:username username es un valor dinámico que se pasa como parámetro al método de respuesta a la ruta.

  1. Modulo de Controller.

Al igual que en el Route crearemos un modulo para el controller, como vemos a continuación.

define(["marionette"], function (Marionette) {

    var Controller = Marionette.Controller.extend({
        initialize : function(options) {
             //TODO: code to initialize
         },
        start: function() {
            //TODO: code to start
        },

        /**
         * Initialized on start, without hash
         * @method
         */
         home :  function () {
            alert('Hello Marionette');
        },
    });

    return Controller;
});

Este modulo es anónimo y extiende del objeto Marionette.Controller como se puede apreciar tenemos los métodos initialize y start para poder realizar tareas que sean requeridas al momento de la creación del controller.

Posteriormente se deben definir las propiedades que serán funciones de respuesta a rutas de nuestra aplicación. En nuestro caso definimos el método hello.

  1. Invocar Route y Controller en aplicación.

Cuando declaramos nuestra aplicación hacemos la carga de los objetos que definen el Router y el Controller, como se muestra a continuación.

// Loading dependences and module to execute Marionette App
require( ["marionette","../modules/AppRouter", "../modules/AppController"], function (Marionette, AppRouter, AppController) {
    // set up the app instance
    var MyApp = new Marionette.Application();

    // initialize the app controller
    var controller = new AppController({});

    // initialize the app router
    MyApp.addInitializer(function(options) {
        // initialize the router
        var router = new AppRouter({
          controller : controller
        });
    });

    MyApp.on("initialize:after", function(){
      // Start Backbone history a necessary step for bookmarkable URL's
      Backbone.history.start();
    });

    MyApp.start({});
});

Aunque los módulos de Route y Controller eran anónimos, haciendo uso de RequireJS podemos hacer carga de los módulos usando la ruta relativa de los módulos como se ve en detalle en la siguiente línea.

require( ["marionette","../modules/AppRouter", "../modules/AppController"], function (Marionette, AppRouter, AppController) {

Los objetos retornados se pasan como parámetro a la función anónima que define la aplicación.

Como se aprecia se procede a crear un instancia del objeto Controller, que sera usada posteriormente en la definición del Router.

// initialize the app controller
var controller = new AppController({});

En el proceso de inicialización de nuestra aplicación MarionetteJS realizamos la creación del Router utilizando el Controller.

// initialize the app router
MyApp.addInitializer(function(options) {
  // initialize the router
  var router = new AppRouter({
    controller : controller
  });
});

Para finalizar luego de terminar la inicialización de nuestra aplicación se debe activar el history de BackboneJS que sera lo que activara el proceso del Routing.

    MyApp.on("initialize:after", function(){
      // Start Backbone history a necessary step for bookmarkable URL's
      Backbone.history.start();
    });

Cuando se cargue la aplicación se desplegara un alert message con le texto “Hello Marionette” y si modifica la URL a index.html#hello/enzo obtendremos una salida similar a la siguiente imagen.

marionette routing sample

Puedes descargar un ejemplo completo de Routing y Controller de https://github.com/enzolutions/marionette-skeleton-app

Espero que haya sido de su agrado.

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.