Su primera aplicación Backbone.js - Selector de servicios

Los marcos MVC del lado del cliente se han vuelto cada vez más populares con el aumento de la complejidad de las aplicaciones web en el navegador. Estos marcos le permiten organizar su JavaScript usando el patrón MVC probado. Backbone.js es uno de los más populares y se está convirtiendo rápidamente en la opción preferida cuando se considera un marco de este tipo.

Hoy vamos a crear un formulario de selección de servicios con Backbone.js, que le permite elegir un conjunto de elementos de una lista. Se calculará un campo de precio total en tiempo real con el precio agregado de los servicios.

¿Qué es Backbone.js?

Backbone.js es una biblioteca que da estructura a las aplicaciones web al proporcionar modelos, colecciones y vistas, todo conectado con eventos personalizados. Conecta su aplicación a su backend a través de una interfaz RESTful JSON y puede obtener y guardar datos automáticamente. En este tutorial no utilizaremos las funciones avanzadas de la biblioteca:todo se almacenará en el lado del cliente. Backbone no reemplaza y no depende de jQuery, pero los dos funcionan muy bien juntos.

Sin embargo, Backbone no resolverá mágicamente sus problemas:aún debe ser inteligente en la forma en que organiza su código, lo que puede ser un problema si no tiene experiencia previa con marcos MVC. Backbone también puede ser una exageración para aplicaciones más pequeñas, donde unas pocas líneas de jQuery serían suficientes, por lo que sería mejor dejarlo para bases de código grandes. La aplicación que estamos construyendo aquí está en el primer campo, pero muestra los conceptos fundamentales detrás del marco.

El HTML

Comenzamos con un documento HTML5 normal. No he agregado la corrección HTML5, por lo que es posible que no se vea bien en los IE más antiguos:

index.html

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Your first Backbone.js App | Tutorialzine </title>

        <!-- Google web fonts -->
        <link href="http://fonts.googleapis.com/css?family=PT+Sans:400,700" rel='stylesheet' />

        <!-- The main CSS file -->
        <link href="assets/css/style.css" rel="stylesheet" />

    </head>

    <body>

        <form id="main" method="post" action="submit.php">
            <h1>My Services</h1>

            <ul id="services">
                <!-- The services will be inserted here -->
            </ul>

            <p id="total">total: <span>$0</span></p>

            <input type="submit" id="order" value="Order" />

        </form>

        <!-- JavaScript Includes -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>

        <script src="assets/js/script.js"></script>

    </body>
</html>

El elemento principal de la página es el formulario. El UL dentro se completará con elementos LI para los servicios y el intervalo dentro del #total el párrafo mantendrá el precio.

Antes de la etiqueta de cierre , he incluido jQuery, Backbone y la biblioteca Underscore (backbone depende de sus potentes funciones de utilidad). Por último viene el archivo script.js, que puedes ver en la siguiente sección.

JavaScript

Esta es la idea general de nuestro código Backbone:

  1. Primero crearemos un modelo de servicio. Tendrá propiedades para el nombre del servicio, el precio y marcado - un campo de estado que muestra si este servicio ha sido elegido o no. Se creará un objeto de esta clase para cada servicio que ofrecemos;
  2. Luego, crearemos una colección Backbone que almacenará todos los servicios. Hará que sea más fácil escuchar eventos en todos los objetos a la vez. En aplicaciones más grandes, escucharía cuándo se insertan o eliminan elementos de la colección y actualiza las vistas en consecuencia. En nuestro caso, como los elementos de la colección están predeterminados, solo escucharemos el cambio evento (que se genera cada vez que marcado se actualiza la propiedad).
  3. Después de esto, definimos una vista para los servicios. Cada vista se asociará con un solo modelo y convertirá sus propiedades en HTML. Escucha los clics y actualiza los marcados propiedad del modelo.
  4. Por último, definimos una vista maestra, que recorre todos los servicios de la colección y crea vistas para ellos. También escucha el evento de cambio en la colección y actualiza el precio total.

Ya que sé que no leyó todo lo anterior, aquí está el código fuente ricamente comentado:

activos/js/script.js

$(function(){

    // Create a model for the services
    var Service = Backbone.Model.extend({

        // Will contain three attributes.
        // These are their default values

        defaults:{
            title: 'My service',
            price: 100,
            checked: false
        },

        // Helper function for checking/unchecking a service
        toggle: function(){
            this.set('checked', !this.get('checked'));
        }
    });

    // Create a collection of services
    var ServiceList = Backbone.Collection.extend({

        // Will hold objects of the Service model
        model: Service,

        // Return an array only with the checked services
        getChecked: function(){
            return this.where({checked:true});
        }
    });

    // Prefill the collection with a number of services.
    var services = new ServiceList([
        new Service({ title: 'web development', price: 200}),
        new Service({ title: 'web design', price: 250}),
        new Service({ title: 'photography', price: 100}),
        new Service({ title: 'coffee drinking', price: 10})
        // Add more here
    ]);

    // This view turns a Service model into HTML. Will create LI elements.
    var ServiceView = Backbone.View.extend({
        tagName: 'li',

        events:{
            'click': 'toggleService'
        },

        initialize: function(){

            // Set up event listeners. The change backbone event
            // is raised when a property changes (like the checked field)

            this.listenTo(this.model, 'change', this.render);
        },

        render: function(){

            // Create the HTML

            this.$el.html('<input type="checkbox" value="1" name="' + this.model.get('title') + '" /> ' + this.model.get('title') + '<span>$' + this.model.get('price') + '</span>');
            this.$('input').prop('checked', this.model.get('checked'));

            // Returning the object is a good practice
            // that makes chaining possible
            return this;
        },

        toggleService: function(){
            this.model.toggle();
        }
    });

    // The main view of the application
    var App = Backbone.View.extend({

        // Base the view on an existing element
        el: $('#main'),

        initialize: function(){

            // Cache these selectors
            this.total = $('#total span');
            this.list = $('#services');

            // Listen for the change event on the collection.
            // This is equivalent to listening on every one of the 
            // service objects in the collection.
            this.listenTo(services, 'change', this.render);

            // Create views for every one of the services in the
            // collection and add them to the page

            services.each(function(service){

                var view = new ServiceView({ model: service });
                this.list.append(view.render().el);

            }, this);   // "this" is the context in the callback
        },

        render: function(){

            // Calculate the total order amount by agregating
            // the prices of only the checked elements

            var total = 0;

            _.each(services.getChecked(), function(elem){
                total += elem.get('price');
            });

            // Update the total price
            this.total.text('$'+total);

            return this;
        }
    });

    new App();

});

Como puede ver, debe extender las clases proporcionadas por Backbone y, en el proceso, anular los métodos que desea realizar de manera diferente (para las vistas, es casi seguro que desee anular el método de representación). Puede ampliarlos aún más y crear jerarquías de clases.

Las vistas pueden crear su propio HTML, como en el caso de ServiceView , o adjuntarse a elementos existentes. La vista principal de la aplicación es App , que está vinculado a #main forma. Inicializa las otras vistas y actualiza el precio total en su método de renderizado.

El PHP

También incluí una línea de PHP que manejará los envíos de formularios. Todo lo que hace es imprimir los nombres de los campos de casilla de verificación seleccionados:

enviar.php

echo htmlspecialchars(implode(array_keys($_POST), ', '));

Puede ampliarlo con cualquier funcionalidad que necesite, como enviar correos electrónicos, insertar los resultados en una base de datos y más.

¡Hemos terminado!

¡Con esto, nuestro formulario de selección de servicios de Backbone está listo! Espero que encuentre útil el formulario y que le brinde una buena visión general del marco, para que pueda saber cuándo es el momento adecuado para usarlo.

Recursos y lecturas adicionales:

  • La documentación de la columna vertebral
  • La documentación del guión bajo
  • Una aplicación de lista de tareas pendientes
  • El libro gratuito Backbone Fundamentals
  • Una lista de tutoriales y ejemplos de Backbone

No