Consejos y patrones de Backbone.js

 

 

 

  • Register!
  • Designing For Complex UI Masterclass, with Vitaly Friedman

  • Índice
    1. Realizar copias profundas de objetos
    2. Crear fachadas a objetos
    3. Almacenar datos que el servidor no conserva
    4. Representar partes de vistas en lugar de vistas completas
    5. Mantenga los modelos independientes de las vistas
    6. Mapeo de parámetros en enrutadores
    7. model.fetch() no borrará su modelo
    8. Los PUT requieren un atributo de identificación
    9. Datos del modelo al cargar la página
    10. Manejo de validación de atributos de modelo fallida
      1. Devolver un objeto de error
      2. Evento de error personalizado de transmisión

    Backbone.js proporciona estructura a las aplicaciones JavaScript, pero deja muchos patrones de diseño y decisiones en manos de los desarrolladores que terminan teniendo problemas comunes cuando comienzan a desarrollar en Backbone.js. En este artículo, Phillip Whisenhunt explorará diferentes patrones de diseño que puede usar en sus aplicaciones Backbone.js y analizará muchos de los errores comunes que hacen tropezar a los desarrolladores.

     

    Backbone.js es un popular marco JavaScript “MV*” de código abierto que ha ganado un impulso significativo desde su primer lanzamiento hace poco más de tres años. Aunque Backbone.js proporciona estructura a las aplicaciones JavaScript, deja muchos patrones de diseño y decisiones en manos del desarrollador, para bien o para mal, y los desarrolladores se topan con muchos problemas comunes cuando comienzan a desarrollar en Backbone.js.

    Por lo tanto, en este artículo, exploraremos diferentes patrones de diseño que puede usar en sus aplicaciones Backbone.js y veremos muchos de los errores comunes que hacen tropezar a los desarrolladores.

    Las aplicaciones, como los edificios, se construyen mejor siguiendo patrones conocidos. (Imagen: Matthew Rutledge )

     

    Realizar copias profundas de objetos

    JavaScript trata todas las variables de tipo primitivo como paso por valor. Entonces, el valor de una variable se pasa cuando se hace referencia a la variable.

    var helloWorld = “Hello World”;var helloWorldCopy = helloWorld;

    Por ejemplo, el código anterior se establecerá helloWorldCopyigual al valor de helloWorld. Por lo tanto, cualquier modificación helloWorldCopyno modificará helloWorld, ya que es una copia. JavaScript trata todas las variables de tipo no primitivo como paso por referencia , lo que significa que JavaScript pasará una referencia de la dirección de memoria de la variable cuando se haga referencia a ella.

    var helloWorld = { ‘hello’: ‘world’}var helloWorldCopy = helloWorld;

    Por ejemplo, el código anterior se establecerá helloWorldCopyigual a la referencia de helloWorldy, como puedes adivinar, cualquier modificación manipularía helloWorldCopydirectamente helloWorld. Si desea tener una copia de helloWorld, deberá crear una copia del objeto.

    Probablemente te estés preguntando: "¿Por qué explica todo este asunto del paso por referencia?" Bueno, Backbone.js no copia objetos , lo que significa que si usted .get()es un objeto de un modelo, ¡cualquier modificación a ese objeto manipulará directamente el objeto! Veamos un ejemplo para ilustrar dónde esto puede convertirse en un problema. Digamos que tienes un Personmodelo como el siguiente:

    var Person = Backbone.Model.extend({ defaults: { 'name': 'John Doe', 'address': { 'street': '1st Street' 'city': 'Austin', 'state': 'TX' 'zipCode': 78701 } }});

    Y digamos que creas un nuevo personobjeto:

    var person = new Person({ 'name': 'Phillip W'});

    Ahora, manipulemos algunos de los atributos del nuevo personobjeto:

    person.set('name', 'Phillip W.', { validate: true });

    El código anterior manipula con éxito el nameatributo del personobjeto. Ahora intentemos manipular la dirección del personobjeto. Sin embargo, antes de hacerlo, agreguemos algo de validación para la dirección.

    var Person = Backbone.Model.extend({ validate: function(attributes) { if(isNaN(attributes.address.zipCode)) return "Address ZIP code must be a number!"; }, defaults: { 'name': 'John Doe', 'address': { 'street': '1st Street' 'city': 'Austin', 'state': 'TX' 'zipCode': 78701 } }});

    Ahora, intentemos manipular la dirección con un código postal incorrecto.

     

    var address = person.get('address');address.zipCode = 'Hello World';// Raises an error since the ZIP code is invalidperson.set('address', address, { validate: true });console.log(person.get('address'));/* Prints an object with these properties.{ 'street': '1st Street' 'city': 'Austin', 'state': 'TX' 'zipCode': 'Hello World'}*/

    ¿Cómo puede ser esto? ¡Nuestra validación ha generado un error! ¿Por qué se siguen cambiando los atributos? Como se mencionó, Backbone.js no copia los atributos del modelo ; simplemente devuelve todo lo que estás pidiendo. Entonces, como puedes adivinar, si solicitas un objeto, obtendrás una referencia a ese objeto, y cualquier manipulación del objeto manipulará directamente el objeto real en el modelo. Esto puede llevarlo rápidamente a una madriguera muy oscura que puede llevarle horas de depuración para diagnosticar.

    Realizar una copia profunda de los objetos del modelo puede evitar que caigas en la trampa de la depuración. (Imagen: David Orban )

    Este problema toma por sorpresa a los desarrolladores que son nuevos en Backbone.js e incluso a los desarrolladores de JavaScript experimentados. Este problema se ha discutido ampliamente en la sección de problemas de GitHub de Backbone.js. Como señala allí Jeremy Ashkenas , realizar una copia profunda es un problema muy difícil de resolver y puede convertirse en una operación costosa para objetos muy grandes y profundos.

    Afortunadamente, jQuery proporciona una implementación de copia profunda $.extend. Además, Underscore.js , una dependencia de Backbone.js, proporciona la _.extendfunción, pero evitaría usarla porque no realiza una copia profunda. Lo-Dash , una versión bifurcada y optimizada de Underscore.js, proporciona una _.clonefunción con la opción de realizar una copia profunda. Sin embargo, suelo $.extendrealizar una copia profunda de cualquier objeto que tome .get()de un modelo usando la siguiente sintaxis. Recuerda pasar true, para que realice una copia profunda del objeto.

    var address = $.extend(true, {}, person.address);

    Ahora tenemos una copia exacta del addressobjeto y podemos modificarlo a nuestro gusto sin preocuparnos por modificar el modelo real. Debe tener en cuenta que este patrón funciona para el ejemplo anterior porque todos los miembros del objeto de dirección son inmutables (números, cadenas, etc.) y que, si bien el ejemplo anterior funciona, debe tener cuidado al copiar en profundidad objetos que contienen objetos. . También debe saber que hay un pequeño impacto en el rendimiento al realizar una copia profunda, pero nunca he visto que esto cause problemas notables. Sin embargo, si está copiando en profundidad objetos masivos, o miles de objetos a la vez, es probable que desee realizar algunos perfiles de rendimiento. Esto nos lleva directamente al siguiente patrón.

    Crear fachadas a objetos

    En el mundo real, los requisitos cambian con frecuencia, al igual que la notación de objetos JavaScript (o JSON ) devuelta por los puntos finales a los que llegan sus modelos y colecciones. Esto puede convertirse en un gran problema en su código base si su vista está estrechamente acoplada al modelo de datos subyacente. Por lo tanto, creo captadores y definidores para todos los objetos .

     

    Las ventajas de este patrón son muchas. Si alguna de las estructuras de datos subyacentes cambia, entonces las capas de vista no deberían tener que actualizarse tanto; Tendrá un punto de acceso a los datos, por lo que es menos probable que se olvide de hacer una copia profunda y su código será más fácil de mantener y depurar. La desventaja es que este patrón puede causar un poco de hinchazón en tus modelos o colecciones.

    Veamos un ejemplo para ilustrar este patrón. Imagine que tenemos un Hotelmodelo que contiene habitaciones y las habitaciones disponibles actualmente, y que queremos poder recuperar habitaciones por tamaño de cama.

    var Hotel = Backbone.Model.extend({ defaults: { "availableRooms": ["a"], "rooms": { "a": { "size": 1200, "bed": "queen" }, "b": { "size": 900, "bed": "twin" }, "c": { "size": 1100, "bed": "twin" } }, getRooms: function() { $.extend(true, {}, this.get("rooms")); }, getRoomsByBed: function(bed) { return _.where(this.getRooms(), { "bed": bed }); } }});

    Ahora imaginemos que mañana publicará su código y descubre que los desarrolladores del punto final olvidaron decirle que la estructura de datos de las habitaciones ha cambiado de un objeto a una matriz. Su código ahora se parece al siguiente.

    var Hotel = Backbone.Model.extend({ defaults: { "availableRooms": ["a"], "rooms": [ { "name": "a", "size": 1200, "bed": "queen" }, { "name": "b", "size": 900, "bed": "twin" }, { "name": "c", "size": 1100, "bed": "twin" } ], getRooms: function() { var rooms = $.extend(true, {}, this.get("rooms")), newRooms = {}; // transform rooms from an array back into an object _.each(rooms, function(room) { newRooms[room.name] = { "size": room.size, "bed": room.bed } }); }, getRoomsByBed: function(bed) { return _.where(this.getRooms(), { "bed": bed }); } }});

    Actualizamos solo una función para transformar la Hotelestructura en la estructura que espera el resto de nuestra aplicación, y toda nuestra aplicación aún se comporta como se esperaba. Si no tuviéramos un captador aquí, es posible que tengamos que actualizar cada punto de acceso a rooms. Lo ideal sería actualizar todas sus funciones para que funcionen con la nueva estructura de datos, pero si tiene poco tiempo y tiene que liberarse, este patrón puede salvarlo.

    Además, este patrón puede considerarse como un patrón de diseño de fachada , porque oculta la complejidad de crear una copia de sus objetos, o como un patrón de diseño de puente , porque puede usarse para transformar datos en lo esperado. Una buena regla general es utilizar captadores y definidores en cualquier cosa que sea un objeto .

     

    Almacenar datos que el servidor no conserva

    Aunque Backbone.js prescribe que los modelos y colecciones se asignan a puntos finales de transferencia de estado representacional (o REST-ful), a veces encontrará que desea almacenar datos en sus modelos o colecciones que no persisten en el servidor. Muchos otros artículos sobre Backbone.js, como “ Consejos de Backbone.js: lecciones de las trincheras ” de Prateek Dayal de SupportBee, describen este patrón. Veamos un ejemplo rápido para ayudar a explicar dónde esto podría resultar útil. Supongamos que tiene una ullista.

    ul lia href="#" data-id="1"One/a/li lia href="#" data-id="2"Two/a/li . . . lia href="#" data-id="n"n/a/li/ul

    Donde nes 200 y cuando el usuario hace clic en uno de los elementos, ese elemento se selecciona y el usuario lo visualiza como el elemento elegido por una selectedclase que se agrega. Un enfoque para esto sería el siguiente:

    var Model = Backbone.Model.extend({ defaults: { items: [ { "name": "One", "id": 1 }, { "name": "Two", "id": 2 }, { "name": "Three", "id": 3 } ] }});var View = Backbone.View.extend({ template: _.template($('#list-template').html()), events: { "#items li a": "setSelectedItem" }, render: function() { $(this.el).html(this.template(this.model.toJSON())); }, setSelectedItem: function(event) { var selectedItem = $(event.currentTarget); // Set all of the items to not have the selected class $('#items li a').removeClass('selected'); selectedItem.addClass('selected'); return false; }});
    script type="template"ul % for(i = items.length - 1; i = 0; i--) { % li a href="#" data-id="%= item[i].id %"%= item[i].name %/a/li% } %/ul/script

    Ahora digamos que queremos averiguar qué elemento se ha seleccionado. Una forma sería recorrer la lista. Pero si la lista es muy larga, esto podría convertirse en una tarea bastante costosa. Por lo tanto, también almacenemos qué elemento se selecciona cuando el usuario hace clic en un elemento de la lista .

    var View = Backbone.View.extend({ initialize: function(options) { // Re-render when the model changes this.model.on('change:items', this.render, this); }, template: _.template($('#list-template').html()), events: { "#items li a": "setSelectedItem" }, render: function() { $(this.el).html(this.template(this.model.toJSON())); }, setSelectedItem: function(event) { var selectedItem = $(event.currentTarget); // Set all of the items to not have the selected class $('#items li a').removeClass('selected'); selectedItem.addClass('selected'); // Store a reference to what item was selected this.selectedItemId = selectedItem.data('id')); return false; }});

    Ahora podemos determinar fácilmente qué elemento se ha seleccionado y no tenemos que atravesar el Modelo de objetos de documento (DOM). Este patrón es extremadamente útil para almacenar datos superfluos de los que quizás desee realizar un seguimiento; Tenga en cuenta también que puede crear modelos y colecciones que no necesariamente tengan puntos finales asociados para almacenar datos de vista extraños. Blog sobre Ajedrez

     

    Las desventajas de este patrón son que si almacena datos extraños en sus modelos o colecciones, en realidad no seguirán una arquitectura RESTful ya que no se asignarán perfectamente a un recurso web; Además, este patrón puede causar un poco de hinchazón en tus objetos; y puede causar un poco de molestia al guardar sus modelos si su punto final acepta estrictamente solo el JSON que espera.

    Quizás se pregunte: "¿Cómo determino si debo colocar los datos adicionales en la vista o en el modelo?". Si los atributos adicionales que está agregando se centran en la representación, como la altura de un contenedor, probablemente deberían agregarse a la vista. Si los atributos tienen algo que ver con el modelo de datos subyacente, es posible que desee incluirlos en el modelo. Por ejemplo, si el ejemplo anterior fuera más sencillo y por alguna razón solo quisiera que los usuarios pudieran seleccionar un rango específico de elementos de la lista de elementos devueltos por el modelo, probablemente introduciría esa lógica en el modelo. En resumen, como ocurre con la mayoría de las cosas, realmente depende de la situación. Puede argumentar a favor de mantener sus modelos verdaderamente fieles a REST y puede argumentar que debe mantener sus puntos de vista lo más tontos posible e introducir tanta lógica en sus modelos.

    Representar partes de vistas en lugar de vistas completas

    Cuando comience a desarrollar aplicaciones Backbone.js, sus vistas normalmente estarán estructuradas de esta manera:

    var View = Backbone.View.extend({ initialize: function(options) { this.model.on('change', this.render, this); }, template: _.template($(‘#template’).html()), render: function() { this.$el.html(template(this.model.toJSON()); $(‘#a’, this.$el).html(this.model.get(‘a’)); $(‘#b’, this.$el).html(this.model.get(‘b’)); }});

    Aquí, cualquier cambio en su modelo activará una nueva representación completa de la vista. Yo practicaba este patrón cuando comencé a desarrollar con Backbone.js. Pero a medida que el código de mi vista crecía en tamaño, rápidamente me di cuenta de que este enfoque no era mantenible ni óptimo porque la vista se volvía a representar por completo cuando cambiaba cualquier atributo del modelo.

    Cuando me encontré con este problema, hice una búsqueda rápida en Google para ver qué habían hecho otros y encontré la publicación del blog de Ian Storm Taylor, " Break Apart Your Backbone.js Render Methods ", en la que describe cómo escuchar cambios de atributos individuales en el modelo. y luego volver a renderizar solo la parte de la vista correspondiente al atributo modificado . Taylor también describe cómo devolver una referencia al objeto para que las funciones de representación individuales se puedan encadenar fácilmente. El ejemplo anterior ahora se transforma en algo mucho más fácil de mantener y con mejor rendimiento porque solo estamos actualizando partes de la vista que corresponden a los atributos del modelo que han cambiado.

     

    var View = Backbone.View.extend({ initialize: function(options) { this.model.on('change:a', this.renderA, this); this.model.on('change:b', this.renderB, this); }, renderA: function() { $(‘#a’, this.$el).html(this.model.get(‘a’)); return this; }, renderB: function() { $(‘#b’, this.$el).html(this.model.get(‘b’)); return this; }, render: function() { this .renderA() .renderB(); }});

    Debo mencionar que muchos complementos, como Backbone.StickIt y Backbone.ModelBinder , proporcionan enlaces clave-valor entre los atributos del modelo y los elementos de vista, lo que puede ahorrarle una gran cantidad de código repetitivo. Entonces, compruébalos si tienes campos de formulario complejos.

    Mantenga los modelos independientes de las vistas

    Como señala Jeremy Ashkenas en uno de los problemas de GitHub de Backbone.js , Backbone.js no impone ninguna separación real de preocupaciones entre la capa de datos y la de vista, excepto que los modelos no se crean con una referencia a su vista. Porque Backbone.js no impone una separación de preocupaciones, ¿debería usted? Yo y muchos otros desarrolladores de Backbone.js, como Oz Katz y Dayal , creemos que la respuesta es abrumadoramente sí: los modelos y las colecciones, la capa de datos, deben ser completamente independientes de las vistas que están vinculadas a ellos, manteniendo una clara separación de preocupaciones. . Si no sigue una separación de preocupaciones, su código base podría convertirse rápidamente en código espagueti, y a nadie le gusta el código espagueti .

    Mantener sus modelos independientes de sus vistas ayudará a prevenir el código espagueti, ¡y a nadie le gusta el código espagueti! (Imagen: Sira Hanchana)

    Mantener su capa de datos completamente independiente de la capa de vista permite una base de código más modular, reutilizable y mantenible. Puede reutilizar y ampliar fácilmente modelos y colecciones en toda su aplicación sin preocuparse por las vistas que los vinculan. Seguir este patrón permite a los desarrolladores nuevos en su proyecto sumergirse rápidamente en el código base , porque sabrán exactamente dónde se realiza la representación y dónde debe residir toda la lógica empresarial de su aplicación.

    Este patrón también aplica el principio de responsabilidad única , que dicta que cada clase debe tener una única responsabilidad, y su responsabilidad debe estar encapsulada en la clase, ya que sus modelos y colecciones deben manejar datos y sus vistas deben manejar la representación.

    Mapeo de parámetros en enrutadores

    La mejor manera de demostrar cómo surgió este patrón es mediante un ejemplo. Digamos que tiene algún tipo de página de búsqueda y que la página de búsqueda permite a los usuarios agregar dos tipos de filtros diferentes, foocada baruno de los cuales tiene una multitud de opciones. Por lo tanto, su estructura de URL comenzaría con este aspecto:

    'search/:foo''search/:bar''search/:foo/:bar'

    Ahora, todas estas rutas usan exactamente la misma vista y modelo, por lo que lo ideal sería que todas usaran la misma función search(). Sin embargo, si examina Backbone.js, no hay ningún tipo de asignación de parámetros; los parámetros simplemente se colocan en la función de izquierda a derecha. Entonces, para que todos usen la misma función, terminarías creando diferentes funciones para asignar correctamente los parámetros search().

     

    routes: { 'search/:foo': 'searchFoo', 'search/:bar': 'searchBar', 'search/:foo/:bar': 'search'},search: function(foo, bar) {},// I know this function will actually still map correctly, but for explanatory purposes, it's left in.searchFoo: function(foo) { this.search(foo, undefined);},searchBar: function(bar) { this.search(undefined, bar);},

    Como puede imaginar, este patrón podría inflar rápidamente sus enrutadores. Cuando me encontré con este problema por primera vez, intenté analizar las definiciones de funciones reales con expresiones regulares para mapear "mágicamente" los parámetros, lo que habría funcionado, pero solo si hubiera seguido restricciones específicas. Entonces, descarté la idea (es posible que aún incluya esto en un complemento de Backbone en algún momento). Abrí un problema en GitHub y Ashkenas sugirió mapear todos los parámetros en la función de búsqueda.

    El código anterior ahora se transforma en algo mucho más fácil de mantener:

    routes: { 'base/:foo': 'search', 'base/:bar': 'search', 'base/:foo/:bar': 'search'},search: function() { var foo, bar, i; for(i = arguments.length - 1; i = 0; i--) { if(arguments[i] === 'something to determine foo') { foo = arguments[i]; continue; } else if(arguments[i] === 'something to determine bar') { bar = arguments[i]; continue; } }},

    Este patrón puede reducir drásticamente la sobrecarga del enrutador. Sin embargo, tenga en cuenta que no funcionará con parámetros que no sean distinguibles. Por ejemplo, si tuviera dos parámetros que fueran ID y siguieran el patrón XXXX-XXXX, no podría identificar qué ID correspondía a qué parámetro.

    model.fetch() no borrará su modelo

    Esto generalmente hace tropezar a aquellos que son nuevos en Backbone.js: model.fetch()no borrará su modelo, sino que ampliará los atributos de su modelo . Por lo tanto, si su modelo tiene atributos xy su recuperación devuelve y y, seguirá en el modelo y solo se actualizará. El siguiente ejemplo visualiza este concepto.zyzxyz

    var Model = Backbone.Model.extend({ defaults: { x: 1, y: 1, z: 1 }});var model = new Model();/* model.attributes yields{ x: 1, y: 1, z: 1} */model.fetch();/* let’s assume that the endpoint returns this{ y: 2, z: 2,} *//* model.attributes now yields{ x: 1, y: 2, z: 2} */

    Los PUT requieren un atributo de identificación

    Este también suele hacer tropezar a los que son nuevos en Backbone.js. Para que sus modelos envíen una solicitud HTTP PUT cuando llame .save(), su modelo debe tener un atributo de ID configurado. Recuerde que el verbo HTTP PUT está diseñado para ser una actualización, por lo que tiene sentido que para enviar una solicitud PUT, su modelo deba tener un ID. En un mundo ideal, todos sus modelos tendrían un atributo de ID perfecto llamado ID, pero los datos JSON que reciba de sus puntos finales probablemente no siempre tendrán ID con nombres perfectos.

     

    Por lo tanto, si necesita actualizar un modelo, asegúrese de que haya una identificación en el modelo antes de guardarlo . Las versiones 0.5 y posteriores de Backbone.js le permiten cambiar el nombre del atributo ID de sus modelos usando idAttribute, en caso de que su punto final no devuelva ID nombrados id.

    Si no puede usar una versión de Backbone.js inferior a 0.5, le sugiero que modifique la parsefunción de su colección o modelo para asignar el atributo ID esperado al ID del atributo. Aquí hay un ejemplo rápido de cómo puede lograr esto modificando su función de análisis. Imaginemos que tiene una colección de automóviles cuyas identificaciones son carID.

    parse: function(response) { _.each(response.cars, function(car, i) { // map the returned ID of carID to the correct attribute ID response.cars[i].id = response.cars[i].carID; }); return response;},

    Datos del modelo al cargar la página

    A veces encontrará que sus modelos o colecciones deben inicializarse con datos al cargar la página. Muchos artículos sobre patrones de Backbone.js, como “ Patrones de Backbone ” de Rico Sta Cruz y “Cómo evitar errores comunes de Backbone.js” de Katz, analizan este patrón. Este patrón se logra fácilmente insertando una secuencia de comandos en la página y representando los datos en atributos de modelo único o JSON, utilizando el lenguaje del lado del servidor de su elección. Por ejemplo, en Rails, uso uno de los siguientes:

    // a single attributevar model = new Model({ hello: });// or to have jsonvar model = new Model();

    El uso de este patrón podría mejorar su clasificación en los motores de búsqueda al mostrar su página “instantáneamente”, y podría acortar drásticamente el tiempo que tarda su aplicación en estar operativa al limitar las solicitudes HTTP iniciales de la aplicación.

    Manejo de validación de atributos de modelo fallida

    Muy a menudo, querrá saber qué atributos del modelo no han superado la validación. Por ejemplo, si tiene un campo de formulario extremadamente complejo, es posible que desee saber qué atributo del modelo no superó la validación para poder resaltar el campo de entrada correspondiente al atributo. Desafortunadamente, alertar a sus puntos de vista sobre qué atributos del modelo no han superado la validación no está integrado directamente en Backbone.js, pero puede usar algunos patrones diferentes para manejar esto.

    Devolver un objeto de error

    Un patrón para notificar a sus vistas qué atributos del modelo no han superado la validación es devolver un objeto con algún tipo de indicador que detalla qué atributo no ha superado la validación, como el siguiente:

    // Inside your modelvalidate: function(attrs) { var errors = []; if(attrs.a 0) { errors.push({ 'message': 'Form field a is messed up!', 'class': 'a' }); } if(attrs.b 0) { errors.push({ 'message': 'Form field b is messed up!', 'class': 'b' }); } if(errors.length) { return errors; }}// Inside your viewthis.model.on('invalid’, function(model, errors) { _.each(errors, function(error, i) { $(‘.’ + error.class).addClass('error'); alert(error.message); });});

    La ventaja de este patrón es que maneja todos los mensajes no válidos en una ubicación. La desventaja es que su método no válido podría convertirse en una declaración grande switchsi iftrata los atributos no válidos de manera diferente.

    Evento de error personalizado de transmisión

    Un patrón alternativo, sugerido por un amigo mío, Derick Bailey , es activar eventos de errores personalizados para cada atributo del modelo. Esto permite que sus vistas se vinculen a eventos de error específicos para atributos individuales:

    // Inside your modelvalidate: function(attrs) { if(attrs.a 0) { this.trigger(‘invalid:a’, 'Form field a is messed up!', this); } if(attrs.b 0) { this.trigger(‘invalid:b’, 'Form field b is messed up!', this); }}// Inside your viewthis.model.on('invalid:a’, function(error) { $(‘a’).addClass('error'); alert(error);});this.model.on('invalid:b’, function(error) { $(‘b’).addClass('error'); alert(error);});

    La ventaja de este patrón es que los enlaces de su vista son explícitos en el tipo de error al que están vinculados, y si tiene instrucciones específicas para cada tipo de error de atributo, puede limpiar su código de vista y hacerlo más fácil de mantener. La única desventaja de este patrón es que sus vistas podrían volverse bastante infladas si no hay muchas diferencias en cómo maneja los diferentes errores de atributos.

    Ambos patrones tienen sus pros y sus contras, y usted debe pensar cuál es mejor para su caso de uso. Si trata todos los errores de validación fallidos de la misma manera, entonce






    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Consejos y patrones de Backbone.js

    Consejos y patrones de Backbone.js

    Register! Designing For Complex UI Masterclass, with Vitaly Friedman Índice Realizar copias profundas de

    programar

    es

    https://aprendeprogramando.es/static/images/programar-consejos-y-patrones-de-backbone-821-0.jpg

    2024-05-20

     

    Consejos y patrones de Backbone.js
    Consejos y patrones de Backbone.js

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20