wake-up-neo.com

Was ist bidirektionale Bindung?

Ich habe viel gelesen, dass Backbone keine bidirektionale Bindung ausführt, aber ich verstehe dieses Konzept nicht genau.

Könnte mir jemand ein Beispiel geben, wie die bidirektionale Bindung in einer MVC-Codebasis funktioniert und wie sie nicht mit Backbone funktioniert?

157
Chris M

Bidirektionale Bindung bedeutet nur, dass:

  1. Wenn Eigenschaften im Modell aktualisiert werden, wird auch die Benutzeroberfläche aktualisiert.
  2. Wenn Benutzeroberflächenelemente aktualisiert werden, werden die Änderungen zurück an das Modell übertragen.

Backbone hat keine "eingebaute" Implementierung von # 2 (obwohl Sie dies sicherlich mit Ereignis-Listenern tun können). Andere Frameworks wie Knockout verdrahten automatisch bidirektionale Bindungen .


In Backbone können Sie auf einfache Weise die Nummer 1 erreichen, indem Sie die Rendermethode einer Ansicht an das Änderungsereignis ihres Modells binden. Um # 2 zu erreichen, müssen Sie dem Eingabeelement auch einen Änderungslistener hinzufügen und im Handler model.set Aufrufen.

Hier ist eine Geige mit bidirektionaler Bindung, die in Backbone eingerichtet wurde.

226
McGarnagle

Bidirektionale Bindung bedeutet, dass alle datenbezogenen Änderungen, die sich auf das Modell auswirken, sofort weitergegeben werden an den übereinstimmenden Ansichten und an den Ansichten vorgenommenen Änderungen (z. B. durch Benutzer) sind sofort wiedergegeben im zugrunde liegenden Modell. Wenn sich App-Daten ändern, ändert sich auch die Benutzeroberfläche und umgekehrt.

Dies ist ein sehr solides Konzept zum Erstellen einer Webanwendung, da die "Modell" -Abstraktion eine sichere atomare Datenquelle ist, die überall in der Anwendung verwendet werden kann. Angenommen, ein Modell, das an eine Ansicht gebunden ist, ändert sich, und die entsprechende Benutzeroberfläche (die Ansicht) gibt dies wieder. egal was. Das passende Teil der Benutzeroberfläche (die Ansicht) kann sicher zum Sammeln von Benutzereingaben/-daten verwendet werden, um die Anwendungsdaten auf dem neuesten Stand zu halten.

Eine gute bidirektionale Bindungsimplementierung sollte diese Verbindung zwischen einem Modell und einigen Ansichten aus Entwicklersicht offensichtlich so einfach wie möglich machen.

Dann ist es durchaus unwahr zu sagen, dass Backbone keine Unterstützung bidirektionale Bindung bietet: Obwohl dies kein Kernmerkmal des Frameworks ist, kann es ganz einfach durchgeführt werden Verwenden von Backbone's Events. Es kostet ein paar explizite Codezeilen für die einfachen Fälle; und kann für komplexere Bindungen sehr gefährlich werden. Hier ist ein einfacher Fall (ungetesteter Code, nur zur Veranschaulichung im laufenden Betrieb geschrieben):

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}

Dies ist ein ziemlich typisches Muster in einer rohen Backbone-Anwendung. Wie man sieht, benötigt es eine anständige Menge (ziemlich standardmäßigen) Codes.

AngularJS und einige andere Alternativen ( Ember , Knockout …) bieten eine bidirektionale Bindung als Erstnutzer-Feature. Sie abstrahieren viele Edge-Cases unter einem bestimmten DSL und geben ihr Bestes, um bidirektionale Bindungen in ihr Ökosystem zu integrieren. Unser Beispiel würde mit AngularJS ungefähr so ​​aussehen (ungetesteter Code, siehe oben):

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

Recht kurz!

Beachten Sie jedoch, dass einige vollwertige bidirektionale Bindungserweiterungen auch für Backbone (in RAW) existieren , subjektive Reihenfolge abnehmender Komplexität): Epoxy , Stickit , ModelBinder

Eine coole Sache mit Epoxy ist beispielsweise, dass Sie Ihre Bindungen (Modellattribute <-> das DOM-Element der Ansicht) entweder in der Vorlage (DOM) oder in der Ansichtsimplementierung (JavaScript) deklarieren können. Einige Leute mögen es nicht, "Direktiven" zum DOM/Template hinzuzufügen (wie die von AngularJS geforderten ng- * Attribute oder die Datenbindungsattribute von Ember).

Am Beispiel von Epoxy kann man die rohe Backbone-Anwendung folgendermaßen überarbeiten (…):

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}

Alles in allem unterstützen so ziemlich alle "Mainstream" -JS-Frameworks die bidirektionale Bindung. Einige von ihnen, wie z. B. Backbone, erfordern zusätzliche Arbeit, damit es funktioniert reibungslos, aber diese sind dieselben, die zunächst keine bestimmte Methode erzwingen. Es geht also wirklich um deinen Geisteszustand.

Vielleicht interessieren Sie sich auch für Flux , eine andere Architektur für Webanwendungen, die das einseitige Binden durch ein kreisförmiges Muster fördert. Es basiert auf dem Konzept der schnellen, ganzheitlichen Neuerstellung von UI-Komponenten bei jeder Datenänderung, um die Kohäsivität sicherzustellen und das Ermitteln des Codes/Datenflusses zu vereinfachen. Im gleichen Trend möchten Sie möglicherweise das Konzept von MVI (Model-View-Intent) überprüfen, z. B. Cycle .

43
chikamichi

McGarnagle hat eine großartige Antwort, und Sie werden seine akzeptieren wollen, aber ich dachte, ich würde (seit Sie gefragt haben) erwähnen, wie die Datenbindung funktioniert.

Es wird im Allgemeinen durch Auslösen von Ereignissen implementiert, wenn eine Änderung an den Daten vorgenommen wird, wodurch die Listener (z. B. die Benutzeroberfläche) aktualisiert werden.

Bei der bidirektionalen Bindung wird dies zweimal ausgeführt, wobei jedoch darauf geachtet wird, dass Sie nicht in einer Ereignisschleife hängen bleiben (bei der durch die Aktualisierung des Ereignisses ein anderes Ereignis ausgelöst wird).

Ich wollte das in einen Kommentar schreiben, aber es wurde ziemlich lang ...

25
Jeff

Tatsächlich unterstützt emberjs die bidirektionale Bindung, eine der leistungsstärksten Funktionen für ein JavaScript-MVC-Framework. Sie können nachsehen, wo in der Bedienungsanleitung binding angegeben ist.

für emberjs besteht das Erstellen einer bidirektionalen Bindung darin, eine neue Eigenschaft mit der Zeichenfolge Binding am Ende zu erstellen und anschließend einen Pfad aus dem globalen Bereich anzugeben:

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

Beachten Sie, dass Bindungen nicht sofort aktualisiert werden. Ember wartet, bis der gesamte Anwendungscode ausgeführt wurde, bevor Änderungen synchronisiert werden. Sie können also eine gebundene Eigenschaft so oft ändern, wie Sie möchten, ohne sich Gedanken über den Aufwand beim Synchronisieren von Bindungen zu machen, wenn Werte vorhanden sind vorübergehend.

Hoffe, es hilft im Umfang der ursprünglichen Antwort ausgewählt.

1
weia design

Erwähnenswert ist, dass es viele verschiedene Lösungen gibt, die bidirektionale Bindung bieten und sehr gut spielen.

Ich habe mit diesem Modellbinder eine angenehme Erfahrung gemacht - https://github.com/theironcook/Backbone.ModelBinder . Dies gibt sinnvolle Standardeinstellungen und dennoch viele benutzerdefinierte JQuery-Selector-Zuordnungen von Modellattributen zu Eingabeelementen.

Es gibt eine erweiterte Liste von Backbone-Erweiterungen/Plugins unter github

0
Daniel