Estado del model de networking troncal cuando está vinculado a un formulario

Estoy construyendo un formulario con Backbone y estoy buscando que valide sus campos en el evento "blur".

Engancharme al evento es bastante fácil, pero lo que me interesa es si el model debe actualizarse o no en el desenfoque o solo cuando se envía el formulario.

Actualización del model borroso

  • model.set({...}, {validate:true});
  • si su model tiene múltiples attributes, la validation se ejecutará para todos ellos, cada vez
  • cuando se crea un nuevo elemento , el estado del model no es tan importante porque probablemente aún no se comparte con ningún otro module
  • al editar un ítem , el model se encuentra en este extraño estado desactualizado / actualizado, dependiendo de dónde se encuentre la persona en el formulario. ¿Qué sucede si el model se comparte entre múltiples modules?

Actualización del model en el envío

  • no se puede usar model.set() para la validation, por lo que el model necesita exponer algunos methods de validation (por ejemplo, MyModel.validZip() )
  • en el envío, a pesar de que todos los campos han sido validados, set() debe llamar a set() para actualizar el model, lo que hará que la validation suceda una vez más (no del todo seguro de que esto sea malo)

He leído un par de cuestiones importantes de Backbone github ( 1 , 2 , 3 ) y los desarrolladores Backbone parecen trazar una línea entre un model y un formulario.

Además, el complemento Backbone.Form parece mantener una propiedad de fields internos para rastrear los campos del formulario y, cuando .commit() , llame a .commit() para actualizar el model.

Entonces parece que actualizar el model en el envío es el mejor enfoque. ¿Es esa la experiencia que has tenido?

Proper UX en forms es complicado. He intentado ambos enfoques en el pasado. En mi opinión, hay una tercera opción: mantener siempre un model sincronizado con el estado de su vista.

Este breve video destaca algunos de mis razonamientos: http://screencast.com/t/qukIe6XW5 .

En este video, estoy escribiendo en un formulario. El formulario se actualiza automáticamente para mostrar cuántos caracteres he escrito y cuántos están permitidos. Es una buena experiencia de usuario proporcionar comentarios instantáneos en lugar de hacer que el usuario elimine el foco del formulario, descubra que tienen errores de validation y luego regrese al formulario. Para lograr esto, necesitarás saber el estado de tu vista en todo momento.

¡Pero no quiero que el estado de mi model se actualice automáticamente! ¡El usuario debe presionar enviar primero!

Parece que presentar otra class de models te facilitaría la vida. Considere crear un model de vista que guarde una reference a la instancia de su model. Con la introducción de un model de vista, podrá registrar los cambios en su vista sin afectar el estado de su model. Esto ayuda a mitigar el riesgo de que sucedan cosas malas y, si algo sale mal, su server podrá detectar los cambios y fallar con la validation del lado del server.

Aquí hay algunos enlaces a mi fuente para hacer una edición in situ:

Verás que le doy a EditPlaylistPromptView un model EditPlaylistPrompt que almacena una reference a la list de reproducción que se está editando. Sin embargo, no modifica directamente esa list de reproducción mientras el usuario está trabajando en la vista. Simplemente actualiza la list de reproducción una vez que pasa la validation. Tenga en count que no estoy revisando el model para la validation, pero podría estarlo, simplemente descuidando ese aspecto.

Aquí hay una foto de cómo me gusta visualizar las cosas. Es completamente cierto que un model debería preocuparse por una visión para hacer cumplir la separación de las preocupaciones. Sin embargo, eso es solo cuando trabajas con 3 capas de objects. Sea más flexible, introduzca una nueva capa intermedia llamada ViewModel y su vida se simplificará:

enter image description here

Actualizar el model en el envío parece ser un mejor enfoque. Backbone es un framework MVC (más de un MV *, pero diseñado para seguir los mismos principios). Dicho esto, el objective de los controlleres es tener una capa separada dedicada a restringir o controlar cómo un usuario interactúa con los datos (model). Entonces, solo dejar que el usuario actualice el model hasta que todo sea válido cumple con la lógica MVC tradicional.

Además, solo está validando una vez que el usuario ha enviado y, básicamente, dijo 'esto es lo que quiero que sean las cosas'. La actualización en blur puede validar preventivamente la información.

Ver wikipedia MVC: "[MVC] divide una aplicación de software dada en tres partes interconectadas para separar las representaciones internas de información de las forms en que se presenta o acepta la información del usuario"

Depende de cómo quiera que los usuarios interactúen con su aplicación. Si desea que las cosas siempre estén sincronizadas (como documentos de Google, por ejemplo), puede actualizar el model en 'cambio' y luego enviarlo al server en 'desenfoque' o con un intervalo de time específico.

Si desea que los usuarios tengan que hacer clic en enviar, sería mejor no actualizar el model hasta que esté listo para enviar datos al back-end.

Solo puedo decir por mi experiencia y esto obviamente va a ser muy dogmático.

No me gusta establecer valores en un model sin preguntar primero al server si un cambio de valor es lo suficientemente válido para comprometerse y, por lo tanto, transmitirlo a todos los modules que eventualmente muestren o dependan del object model en cuestión. Es muy posible que el server no acepte una input aunque haya superado todas las condiciones que el cliente pudo verificar (por ejemplo, un correo electrónico válido, pero no exclusivo en el server). Una vez dicho esto, parte de la información debe y puede validarse inmediatamente sin preguntar primero al server. Al final, es probable que sea un "lo mejor de ambos mundos". Sabiduría de mierda, lo sé;).

Lo más importante aquí es la capacidad de retroceder a un estado válido anterior, sin importar qué parte del process causó la invalidation. Me refiero a este extraño estado anticuado / actualizado que mencionaste anteriormente. Solo podemos estar absolutamente seguros sobre la corrección de un cambio si "la computadora dice que sí" (back-end, eso es).

Ahora, ¿cómo lograr eso? Aquí hay dos enfoques (requisito previo para ambos ejemplos: todos los objects del model tienen un atributo de ID único y si no estamos hablando de "crear"):

Modifique un object temporal, duplique al object real si se valida.

  • Deje que el formulario represente un nuevo object model, sin importar si estamos hablando de "actualizar" o "crear". Puede distinguir perfectamente entre los dos al pedir la identificación más adelante:

     // update var tempModel = new MyModel(modelToUpdate.serialize()); // or create var tempModel = new MyModel(); 
  • set y / o submit los valores del object dependiendo de la experiencia del usuario que desee proporcionar. Me gustaría tener el process de validation lo más general posible y siempre validar el object (todos y cada par key / valor) como un todo. Más sobre eso un poco más tarde.

  • En caso de un process de modificación válido (y completo), vuelva a reflejar los cambios en su object model real o cree uno nuevo:

     var model; if (tempModel.isValid() === false) { // report Error } else if (tempModel.get('id')) { model = modelToUpdate.set(tempModel.serialize()).save(); } else { model = tempModel.save(); // do what you got to do with a new model object } 
  • Principales inconvenientes: siempre que no realice un seguimiento del object de model creado temporalmente, otras partes de la aplicación no tendrán conocimiento de los próximos cambios.

Mantener el estado actual en un object temporal, retroceder a su estado si la validation falla.

  • Guarde el estado actual y, con suerte, válido del object model antes de que se inicie el process de modificación:

     var currentlyValid = new MyModel(modelToUpdate.serialize()); 
  • set y / o submit el object real como mejor le parezca. Una vez más, no debería preocuparse demasiado por los pares key / valor específicos, pero asegúrese de que todo el object sea válido. La principal ventaja aquí es que otras partes de la aplicación que dependen del object en cuestión o que muestran el object en cuestión permanecerán sincronizadas. Principal desventaja: debe manejar la creación de nuevos elementos por separado.

  • Piérdete del object temporal si las modificaciones se validaron. De lo contrario, retroceda al estado previamente guardado.

     if (modelToUpdate.isValid()) { var currentlyValid = null; modelToUpdate.save(); } else { modelToUpdate.set(currentlyValid.serialize()); } 
  • Estafa mayor: no puedo pensar en una forma simplificada de crear nuevos objects con este enfoque. Depende de la implementación, supongo.

Yo, por mi parte, prefiero el primer enfoque. Si todo se trata de sincronizar otras partes de su aplicación que se supone que muestran los cambios en un object model con el object temporal actual en desenfoque , se podría establecer un object model de aplicación que tenga una propiedad que apunte a este último y active events de cambio cada vez que se modifica el object temporal:

 var app = MyApplication({ modelThatIsGettingModified: <Reference to the temp object>; }); 

¿Por qué no usamos Atributos previousAttributes para retroceder?

Debido a que cada llamada set que pasó la validation del lado del cliente modificará la devolución de esta propiedad del model, sin importar si el server completo fue confirmado por el server o no.

Una palabra sobre la validation

Dado el hecho de que el método de validation en los models Backbone …

… no se ha definido, y se le anima a anularlo con su lógica de validation personalizada, si tiene alguna que se pueda realizar en JavaScript … ( documentos Backbone de origen)

… Sugeriría que siempre valide contra todos los pares key / valor. Puede causar algunos gastos generales, eso es seguro, pero esto le permitirá unificar el process de validation. Estoy muy consciente de 1 , 2 y 3 , pero seamos honestos, este tipo de cosas no ralentizarán su aplicación siempre y cuando mantenga el DOM bajo control. Tener un process de validation simplificado es mucho más importante aquí. Si este tipo de networkingundancias comienzan a tener un impacto en el performance de su cosa, probablemente no debería utilizar Backbone en absoluto en mi humilde opinión .