O que é uma ligação bidirecional?


173

Eu li muito que o Backbone não faz ligação bidirecional, mas não entendo exatamente esse conceito.

Alguém poderia me dar um exemplo de como a ligação bidirecional funciona em uma base de código MVC e como não funciona com o Backbone?

Respostas:


249

A ligação bidirecional significa apenas que:

  1. Quando as propriedades no modelo são atualizadas, a UI também.
  2. Quando os elementos da interface do usuário são atualizados, as alterações são propagadas de volta ao modelo.

O backbone não possui uma implementação "inserida" do nº 2 (embora você certamente possa fazê-lo usando ouvintes de eventos). Outras estruturas, como o Knockout, ligam as ligações bidirecionais automaticamente .


No Backbone, você pode facilmente alcançar o número 1 vinculando o método "render" de uma exibição ao evento "change" do modelo. Para alcançar o número 2, você também precisa adicionar um ouvinte de alterações ao elemento de entrada e chamar model.seto manipulador.

Aqui está um violino com ligação bidirecional configurado no Backbone.


25
A resposta é tão dolorosamente óbvia quando você a vê. Muito obrigado por dedicar um tempo para fornecer uma resposta e um exemplo claros.
Chris M

E com o Firebase vem ... ligação de dados de três vias -> Exibir, Modelo, Banco de Dados. Apenas pensei que era bem arrumado.
Levi Fuller

Conciso e curto. +1
Karan_powered_by_RedBull

46

Ligação bidirecional significa que quaisquer alterações relacionadas aos dados que afetam o modelo são propagadas imediatamente para as visões correspondentes e que quaisquer alterações feitas nas visões (por exemplo, pelo usuário) são refletidas imediatamente no modelo subjacente . Quando os dados do aplicativo são alterados, o mesmo acontece com a interface do usuário e vice-versa.

Esse é um conceito muito sólido para criar um aplicativo da Web, pois torna a abstração do "Modelo" uma fonte de dados atômica segura para uso em qualquer lugar do aplicativo. Digamos, se um modelo, vinculado a uma visualização, mudar, sua parte correspondente da interface do usuário (a visualização) refletirá isso, não importa o quê . E a parte correspondente da interface do usuário (a visualização) pode ser usada com segurança como um meio de coletar entradas / dados do usuário, de modo a manter os dados do aplicativo atualizados.

Uma boa implementação de ligação bidirecional deve obviamente tornar essa conexão entre um modelo e algumas visualizações o mais simples possível, do ponto de vista do desenvolvedor.

É então falso dizer que o Backbone não suporta ligação bidirecional: embora não seja um recurso principal da estrutura, ele pode ser executado simplesmente usando os Eventos do Backbone. Custa algumas linhas explícitas de código para os casos simples; e pode se tornar bastante perigoso para ligações mais complexas. Aqui está um caso simples (código não testado, escrito em tempo real apenas para fins de ilustração):

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}

Esse é um padrão bastante típico em um aplicativo Backbone bruto. Como se pode ver, requer uma quantidade decente de código (bastante padrão).

O AngularJS e algumas outras alternativas ( Ember , Knockout ...) fornecem ligação bidirecional como um recurso de primeiro cidadão. Eles abstraem muitos casos extremos sob alguma DSL e fazem o melhor para integrar a ligação bidirecional em seu ecossistema. Nosso exemplo ficaria assim com o AngularJS (código não testado, veja acima):

<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: ''}

Bastante curto!

Mas, estar ciente de que alguns de pleno direito extensões de ligação de duas vias existem para Backbone bem (em ordem cru, subjetiva de diminuir a complexidade): Epoxy , StickIt , ModelBinder ...

Uma coisa interessante com o Epoxy, por exemplo, é que ele permite que você declare suas ligações (atributos de modelo <-> elemento DOM da visualização) dentro do modelo (DOM) ou na implementação da visualização (JavaScript). Algumas pessoas não gostam de adicionar "diretivas" ao DOM / modelo (como os atributos ng- * exigidos pelo AngularJS ou os atributos de ligação de dados do Ember).

Tomando o Epóxi como exemplo, pode-se refazer o aplicativo Backbone bruto em algo como isto (…):

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}

Em suma, praticamente todas as estruturas JS "mainstream" suportam ligação bidirecional. Alguns deles, como o Backbone, exigem algum trabalho extra para fazê-lo funcionar sem problemas , mas esses são os mesmos que não impõem uma maneira específica de fazê-lo, para começar. Portanto, é realmente sobre o seu estado de espírito.

Além disso, você pode estar interessado no Flux , uma arquitetura diferente para aplicativos da Web que promove a ligação unidirecional por meio de um padrão circular. Ele se baseia no conceito de re-renderização rápida e holística dos componentes da interface do usuário em qualquer alteração de dados para garantir coesão e facilitar o raciocínio sobre o código / fluxo de dados. Na mesma tendência, convém verificar o conceito de MVI (Model-View-Intent), por exemplo, Ciclo .


3
Muitos desenvolvedores, especialmente os desenvolvedores do React / Flux, não consideram a ligação bidirecional um padrão seguro para a criação de aplicativos em grande escala.
Andy

28

McGarnagle tem uma ótima resposta, e você vai querer aceitar a dele, mas pensei em mencionar (desde que você perguntou) como funciona a ligação de dados.

Geralmente é implementado disparando eventos sempre que uma alteração é feita nos dados, o que faz com que os ouvintes (por exemplo, a interface do usuário) sejam atualizados.

A ligação bidirecional funciona fazendo isso duas vezes, com um pouco de cuidado para garantir que você não fique preso em um loop de eventos (onde a atualização do evento faz com que outro evento seja acionado).

Eu ia colocar isso em um comentário, mas estava ficando muito longo ...


2

Na verdade, emberjsoferece suporte à ligação bidirecional, que é um dos recursos mais poderosos para uma estrutura MVC javascript. Você pode conferir onde está mencionado bindingno manual do usuário.

para emberjs, criar ligação bidirecional é criar uma nova propriedade com a sequência Binding no final e especificar um caminho no escopo 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

Observe que as ligações não são atualizadas imediatamente. O Ember espera até que todo o código do aplicativo termine a execução antes de sincronizar as alterações, para que você possa alterar uma propriedade vinculada quantas vezes quiser, sem se preocupar com a sobrecarga de sincronizar ligações quando os valores são transitórios.

Espero que ajude na extensão da resposta original selecionada.


1

Vale ressaltar que existem muitas soluções diferentes que oferecem vinculação bidirecional e funcionam muito bem.

Tive uma experiência agradável com este fichário de modelo - https://github.com/theironcook/Backbone.ModelBinder . que fornece aos padrões sensíveis ainda muito mapeamento de seletor de jquery personalizado dos atributos do modelo para os elementos de entrada.

Há uma lista mais extensa de extensões de backbone / plugins no github

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.