Che cos'è l'associazione a due vie?


173

Ho letto molte cose che Backbone non esegue il binding bidirezionale, ma non capisco esattamente questo concetto.

Qualcuno potrebbe darmi un esempio di come funziona l'associazione bidirezionale in una base di codice MVC e come non funziona con Backbone?

Risposte:


249

L'associazione a due vie significa solo che:

  1. Quando le proprietà del modello vengono aggiornate, anche l'interfaccia utente.
  2. Quando gli elementi dell'interfaccia utente vengono aggiornati, le modifiche vengono propagate al modello.

Backbone non ha un'implementazione "al forno" di # 2 (anche se puoi certamente farlo usando i listener di eventi). Altri framework come Knockout collegano automaticamente la rilegatura bidirezionale .


In Backbone, puoi facilmente ottenere il n. 1 vincolando il metodo "render" di una vista all'evento "change" del suo modello. Per raggiungere il n. 2, è inoltre necessario aggiungere un listener di modifica all'elemento di input e chiamare model.setil gestore.

Ecco un violino con attacco bidirezionale impostato in Backbone.


25
La risposta è così penosamente ovvia una volta che la vedi. Grazie mille per aver dedicato del tempo a fornire una risposta chiara e un esempio.
Chris M,

E con Firebase arriva ... database a 3 vie -> Visualizza, Modello, Database. Ho pensato che fosse abbastanza pulito.
Levi Fuller,

Conciso e breve. +1
Karan_powered_by_RedBull

46

L'associazione a due vie significa che qualsiasi modifica relativa ai dati che influenza il modello viene immediatamente propagata alle viste corrispondenti e che eventuali modifiche apportate alle viste (ad esempio, l'utente) si riflettono immediatamente nel modello sottostante . Quando i dati delle app cambiano, cambia anche l'interfaccia utente e viceversa.

Questo è un concetto molto solido per costruire un'applicazione web, perché rende l'astrazione del "Modello" una fonte di dati atomica sicura da usare ovunque all'interno dell'applicazione. Dì, se un modello, associato a una vista, cambia, allora il suo pezzo corrispondente dell'interfaccia utente (la vista) lo rifletterà, non importa quale . E la parte corrispondente dell'interfaccia utente (la vista) può essere tranquillamente utilizzata come mezzo per raccogliere input / dati dell'utente, in modo da mantenere aggiornati i dati dell'applicazione.

Una buona implementazione vincolante a due vie dovrebbe ovviamente rendere questa connessione tra un modello e alcune viste il più semplice possibile, dal punto di vista dello sviluppo.

È quindi falso affermare che Backbone non supporta l' associazione bidirezionale: sebbene non sia una caratteristica fondamentale del framework, può essere eseguita semplicemente usando gli Eventi di Backbone. Costa alcune righe esplicite di codice per i casi semplici; e può diventare piuttosto pericoloso per attacchi più complessi. Ecco un semplice caso (codice non testato, scritto al volo solo a scopo illustrativo):

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}

Questo è un modello abbastanza tipico in un'applicazione Backbone non elaborata. Come si può vedere, richiede una discreta quantità di codice (piuttosto standard).

AngularJS e alcune altre alternative ( Ember , Knockout ...) forniscono un'associazione bidirezionale come funzionalità per il primo cittadino. Estraggono molti casi limite sotto alcuni DSL e fanno del loro meglio per integrare l'associazione bidirezionale nel loro ecosistema. Il nostro esempio sarebbe simile a questo con AngularJS (codice non testato, vedi sopra):

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

Piuttosto breve!

Tuttavia, tieni presente che esistono alcune estensioni di rilegatura a due vie a pieno titolo anche per Backbone (in ordine grezzo, soggettivo di complessità decrescente): Epoxy , Stickit , ModelBinder ...

Una cosa interessante di Epoxy, ad esempio, è che ti consente di dichiarare i tuoi legami (attributi del modello <-> elemento DOM della vista) all'interno del modello (DOM) o nell'implementazione della vista (JavaScript). Ad alcune persone non piace aggiungere "direttive" al modello DOM / (come gli attributi ng- * richiesti da AngularJS o gli attributi di associazione dei dati di Ember).

Prendendo l'Epoxy come esempio, si può rielaborare l'applicazione Backbone grezza in qualcosa del genere (...):

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}

Tutto sommato, praticamente tutti i framework JS "mainstream" supportano l'associazione bidirezionale. Alcuni di essi, come Backbone, richiedono del lavoro extra per farlo funzionare senza problemi , ma quelli sono gli stessi che non impongono un modo specifico per farlo, per cominciare. Quindi si tratta davvero del tuo stato d'animo.

Inoltre, potresti essere interessato a Flux , un'architettura diversa per le applicazioni Web che promuove l'associazione unidirezionale attraverso un modello circolare. Si basa sul concetto di re-rendering rapido e olistico dei componenti dell'interfaccia utente in seguito a qualsiasi modifica dei dati per garantire la coesione e facilitare la motivazione del codice / flusso di dati. Nella stessa tendenza, potresti voler controllare il concetto di MVI (Model-View-Intent), ad esempio Cycle .


3
Molti sviluppatori, in particolare gli sviluppatori React / Flux, non considerano l'associazione bidirezionale un modello sicuro per la creazione di app su larga scala.
Andy,

28

McGarnagle ha un'ottima risposta e vorrai accettare la sua, ma ho pensato di menzionare (da quando hai chiesto) come funziona il database.

In genere viene implementato attivando eventi ogni volta che viene apportata una modifica ai dati, che quindi aggiorna i listener (ad es. L'interfaccia utente).

La rilegatura bidirezionale funziona in questo modo due volte, con un po 'di attenzione per assicurarsi di non rimanere bloccati in un loop di eventi (in cui l'aggiornamento dall'evento provoca l'attivazione di un altro evento).

Lo avrei inserito in un commento, ma stava diventando piuttosto lungo ...


2

In realtà emberjssupporta l'associazione bidirezionale, che è una delle funzionalità più potenti per un framework MVC javascript. Puoi verificarlo dove menzionandolo bindingnella sua guida per l'utente.

per emberjs, creare un'associazione a due vie significa creare una nuova proprietà con la stringa Binding alla fine, quindi specificare un percorso dall'ambito globale:

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

Si noti che i binding non si aggiornano immediatamente. Ember attende il completamento dell'esecuzione di tutto il codice dell'applicazione prima di sincronizzare le modifiche, quindi è possibile modificare una proprietà associata tutte le volte che si desidera senza preoccuparsi dell'overhead della sincronizzazione dei bind quando i valori sono transitori.

Spero che aiuti in estensione della risposta originale selezionata.


1

Vale la pena ricordare che ci sono molte soluzioni diverse che offrono un legame a due vie e giocano davvero bene.

Ho avuto un'esperienza piacevole con questo modello di raccoglitore - https://github.com/theironcook/Backbone.ModelBinder . che fornisce impostazioni predefinite ragionevoli eppure un sacco di mappature personalizzate del selettore jquery degli attributi del modello sugli elementi di input.

C'è un elenco più esteso di estensioni / plugin backbone su github

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.