¿Qué es la unión bidireccional?

173

He leído mucho que Backbone no hace enlace bidireccional, pero no entiendo exactamente este concepto.

¿Podría alguien darme un ejemplo de cómo funciona el enlace bidireccional en una base de código MVC y cómo no funciona con Backbone?

Chris M
fuente

Respuestas:

249

La unión bidireccional solo significa que:

  1. Cuando las propiedades en el modelo se actualizan, también lo hace la interfaz de usuario.
  2. Cuando los elementos de la interfaz de usuario se actualizan, los cambios se propagan de nuevo al modelo.

Backbone no tiene una implementación "integrada" del n. ° 2 (aunque ciertamente puede hacerlo utilizando oyentes de eventos). Otros marcos como Knockout conectan automáticamente el enlace bidireccional .


En Backbone, puede alcanzar fácilmente el n. ° 1 vinculando el método "render" de una vista al evento "cambio" de su modelo. Para lograr el n. ° 2, también debe agregar un detector de cambios al elemento de entrada y llamar model.setal controlador.

Aquí hay un Fiddle con enlace bidireccional configurado en Backbone.

McGarnagle
fuente
25
La respuesta es tan dolorosamente obvia una vez que la ves. Muchas gracias por tomarse el tiempo para proporcionar una respuesta clara y un ejemplo.
Chris M
Y con Firebase viene ... Enlace de datos de 3 vías -> Ver, Modelo, Base de datos. Solo pensé que era bastante bueno.
Levi Fuller
Conciso y corto. +1
Karan_powered_by_RedBull
46

El enlace bidireccional significa que cualquier cambio relacionado con los datos que afecte al modelo se propaga inmediatamente a la (s) vista (s) coincidente (s), y que cualquier cambio realizado en la (s) vista (s) (por ejemplo, por el usuario) se refleja inmediatamente en el modelo subyacente . Cuando los datos de la aplicación cambian, también lo hace la interfaz de usuario, y viceversa.

Este es un concepto muy sólido para construir una aplicación web además, porque hace que la abstracción "Modelo" sea una fuente de datos atómica segura para usar en todas partes dentro de la aplicación. Digamos, si un modelo, vinculado a una vista, cambia, entonces su parte correspondiente de la IU (la vista) reflejará eso, no importa qué . Y la parte correspondiente de la interfaz de usuario (la vista) se puede utilizar de forma segura como un medio para recopilar datos / entradas del usuario, a fin de mantener actualizados los datos de la aplicación.

Obviamente, una buena implementación de enlace bidireccional debería hacer que esta conexión entre un modelo y algunas vistas sea lo más simple posible, desde el punto de vista del desarrollador.

Entonces es bastante falso decir que Backbone no es compatible con el enlace bidireccional: aunque no es una característica central del marco, se puede realizar simplemente usando los eventos de Backbone. Cuesta unas pocas líneas explícitas de código para los casos simples; y puede volverse bastante peligroso para enlaces más complejos. Aquí hay un caso simple (código no probado, escrito sobre la marcha solo por el bien de la ilustración):

Model = Backbone.Model.extend
  defaults:
    data: ''

View = Backbone.View.extend
  template: _.template("Edit the data: <input type='text' value='<%= data %>' />")

  events:
    # Listen for user inputs, and edit the model.
    'change input': @setData

  initialize: (options) ->
    # Listen for model's edition, and trigger UI update
    @listenTo @model, 'change:data', @render

  render: ->
    @$el.html @template(@model.attributes)
    @

  setData: (e) =>
    e.preventDefault()
    @model.set 'data', $(e.currentTarget).value()

model: new Model()
view = new View {el: $('.someEl'), model: model}

Este es un patrón bastante típico en una aplicación Backbone sin procesar. Como se puede ver, requiere una cantidad decente de código (bastante estándar).

AngularJS y algunas otras alternativas ( Ember , Knockout ...) proporcionan enlace bidireccional como una característica de primer ciudadano. Resumen muchos casos extremos en algunas DSL y hacen todo lo posible para integrar la unión bidireccional dentro de su ecosistema. Nuestro ejemplo se vería así con AngularJS (código no probado, ver arriba):

<div ng-app="app" ng-controller="MainCtrl">
  Edit the data:
  <input name="mymodel.data" ng-model="mymodel.data">
</div>
angular.module('app', [])
  .controller 'MainCtrl', ($scope) ->
    $scope.mymodel = {data: ''}

¡Mas bien corto!

Pero tenga en cuenta que también existen algunas extensiones de enlace bidireccionales completas para Backbone (en un orden bruto y subjetivo de complejidad decreciente): Epoxy , Stickit , ModelBinder ...

Una cosa interesante con Epoxy, por ejemplo, es que le permite declarar sus enlaces (atributos del modelo <-> elemento DOM de la vista) dentro de la plantilla (DOM) o dentro de la implementación de la vista (JavaScript). A algunas personas no les gusta agregar "directivas" al DOM / plantilla (como los atributos ng- * requeridos por AngularJS o los atributos de enlace de datos de Ember).

Tomando Epoxy como ejemplo, uno puede volver a trabajar la aplicación Backbone sin procesar en algo como esto (...):

Model = Backbone.Model.extend
  defaults:
    data: ''

View = Backbone.Epoxy.View.extend
  template: _.template("Edit the data: <input type='text' />")
  # or, using the inline form: <input type='text' data-bind='value:data' />

  bindings:
    'input': 'value:data'

  render: ->
    @$el.html @template(@model.attributes)
    @

model: new Model()
view = new View {el: $('.someEl'), model: model}

En general, casi todos los frameworks JS "convencionales" admiten enlaces bidireccionales. Algunos de ellos, como Backbone, requieren un poco de trabajo extra para que funcione sin problemas , pero para empezar, son los mismos que no imponen una forma específica de hacerlo. Entonces se trata realmente de tu estado mental.

Además, puede estar interesado en Flux , una arquitectura diferente para aplicaciones web que promueve el enlace unidireccional a través de un patrón circular. Se basa en el concepto de una representación rápida y holística de los componentes de la interfaz de usuario en cualquier cambio de datos para garantizar la coherencia y facilitar el razonamiento sobre el código / flujo de datos. En la misma tendencia, es posible que desee comprobar el concepto de MVI (Model-View-Intent), por ejemplo, Cycle .

chikamichi
fuente
3
Muchos desarrolladores, especialmente los desarrolladores de React / Flux no consideran el enlace bidireccional como un patrón seguro para crear aplicaciones a gran escala.
Andy
28

McGarnagle tiene una gran respuesta, y querrás aceptar la suya, pero pensé que mencionaría (ya que me preguntaste) cómo funciona la vinculación de datos.

Generalmente se implementa disparando eventos cada vez que se realiza un cambio en los datos, lo que hace que los oyentes (por ejemplo, la interfaz de usuario) se actualicen.

El enlace bidireccional funciona haciendo esto dos veces, con un poco de cuidado para garantizar que no se quede atrapado en un bucle de eventos (donde la actualización del evento provoca que se active otro evento).

Iba a poner esto en un comentario, pero se estaba haciendo bastante largo ...

Jeff
fuente
2

En realidad, emberjsadmite el enlace bidireccional, que es una de las características más potentes para un marco MVC de JavaScript. Puede consultarlo donde se menciona bindingen su guía del usuario.

para emberjs, crear un enlace bidireccional es crear una nueva propiedad con el enlace de cadena al final y luego especificar una ruta desde el ámbito global:

App.wife = Ember.Object.create({
  householdIncome: 80000
});

App.husband = Ember.Object.create({
  householdIncomeBinding: 'App.wife.householdIncome'
});

App.husband.get('householdIncome'); // 80000

// Someone gets raise.
App.husband.set('householdIncome', 90000);
App.wife.get('householdIncome'); // 90000

Tenga en cuenta que los enlaces no se actualizan de inmediato. Ember espera hasta que todo el código de su aplicación haya terminado de ejecutarse antes de sincronizar los cambios, por lo que puede cambiar una propiedad enlazada tantas veces como desee sin preocuparse por la sobrecarga de los enlaces de sincronización cuando los valores son transitorios.

Espero que ayude en la extensión de la respuesta original seleccionada.

diseño weia
fuente
1

Vale la pena mencionar que hay muchas soluciones diferentes que ofrecen un enlace bidireccional y juegan muy bien.

He tenido una experiencia agradable con este modelo de carpeta: https://github.com/theironcook/Backbone.ModelBinder . lo que proporciona valores predeterminados razonables pero una gran cantidad de mapeo de jquery selector personalizado de atributos de modelo a elementos de entrada.

Hay una lista más extendida de extensiones / complementos de red troncal en github

Daniel
fuente