Was ist bidirektionale Bindung?

173

Ich habe viel gelesen, dass Backbone keine bidirektionale Bindung durchfü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 dies nicht mit Backbone funktioniert?

Chris M.
quelle

Antworten:

249

Zweiwege-Bindung bedeutet nur Folgendes:

  1. Wenn Eigenschaften im Modell aktualisiert werden, wird auch die Benutzeroberfläche aktualisiert.
  2. Wenn UI-Elemente aktualisiert werden, werden die Änderungen wieder an das Modell weitergegeben.

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


In Backbone können Sie leicht die Nummer 1 erreichen, indem Sie die "Render" -Methode einer Ansicht an das "Änderungs" -Ereignis ihres Modells binden. Um # 2 zu erreichen, müssen Sie dem Eingabeelement auch einen Änderungslistener hinzufügen und model.setden Handler aufrufen .

Hier ist eine Geige mit Zwei-Wege-Bindung, die in Backbone eingerichtet wurde.

McGarnagle
quelle
25
Die Antwort ist so schmerzlich offensichtlich, wenn Sie sie sehen. Vielen Dank, dass Sie sich die Zeit genommen haben, eine klare Antwort und ein Beispiel zu geben.
Chris M
Und mit Firebase kommt ... 3-Wege-Datenbindung -> Ansicht, Modell, Datenbank. Ich dachte nur, das wäre ziemlich ordentlich.
Levi Fuller
Prägnant und kurz. +1
Karan_powered_by_RedBull
46

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

Dies ist ein sehr solides Konzept, um eine Webanwendung darauf aufzubauen, da es die "Modell" -Abstraktion zu einer sicheren atomaren Datenquelle macht, die überall in der Anwendung verwendet werden kann. Angenommen, wenn sich ein an eine Ansicht gebundenes Modell ändert, spiegelt dies die entsprechende Benutzeroberfläche (die Ansicht) wider, egal was passiert . Und das passende Teil der Benutzeroberfläche (die Ansicht) kann sicher als Mittel 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 Sicht des Entwicklers offensichtlich so einfach wie möglich machen.

Es ist dann ganz falsch zu sagen , dass Backbone nicht nicht unterstützt Zwei-Wege - Bindung: Während nicht eine Kernfunktion des Rahmens, kann es ganz einfach durchgeführt werden Backbone des Events though. Für die einfachen Fälle kostet es einige explizite Codezeilen. und kann für komplexere Bindungen ziemlich gefährlich werden. Hier ist ein einfacher Fall (ungetesteter Code, der nur zur Veranschaulichung im laufenden Betrieb geschrieben wurde):

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 sehen kann, erfordert es eine anständige Menge an (ziemlich normalem) Code.

AngularJS und einige andere Alternativen ( Ember , Knockout …) bieten eine bidirektionale Bindung als First-Citizen-Funktion. Sie abstrahieren viele Randfälle unter DSL und geben ihr Bestes, um die bidirektionale Bindung 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 es auch für Backbone einige vollwertige Zwei-Wege-Bindungserweiterungen gibt (in roher, subjektiver Reihenfolge abnehmender Komplexität): Epoxy , Stickit , ModelBinder

Eine coole Sache bei Epoxy ist beispielsweise, dass Sie Ihre Bindungen (DOM-Element der Modellattribute <-> view) entweder innerhalb der Vorlage (DOM) oder innerhalb der Ansichtsimplementierung (JavaScript) deklarieren können. Einige Leute mögen es nicht, dem DOM / der Vorlage "Direktiven" hinzuzufügen (wie die von AngularJS benötigten ng- * -Attribute oder die Datenbindungsattribute von Ember).

Am Beispiel von Epoxy kann man die rohe Backbone-Anwendung in etwa so ü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 reibungslos funktioniert , aber es sind dieselben, die zunächst keine bestimmte Methode erzwingen. Es geht also wirklich um Ihren Geisteszustand.

Möglicherweise interessieren Sie sich auch für Flux , eine andere Architektur für Webanwendungen, die die Einwegbindung über ein kreisförmiges Muster fördert. Es basiert auf dem Konzept einer schnellen, ganzheitlichen Neuwiedergabe von UI-Komponenten bei jeder Datenänderung, um die Kohäsivität sicherzustellen und das Nachdenken über den Code / Datenfluss zu erleichtern. Im gleichen Trend möchten Sie möglicherweise das Konzept von MVI (Model-View-Intent) überprüfen, z. B. Cycle .

Chikamichi
quelle
3
Viele Entwickler, insbesondere React / Flux-Entwickler, betrachten die bidirektionale Bindung nicht als sicheres Muster für die Erstellung umfangreicher Apps.
Andy
28

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

Es wird im Allgemeinen implementiert, indem Ereignisse ausgelöst werden, wenn Änderungen an den Daten vorgenommen werden, wodurch die Listener (z. B. die Benutzeroberfläche) aktualisiert werden.

Die bidirektionale Bindung funktioniert zweimal, wobei sorgfältig darauf geachtet wird, dass Sie nicht in einer Ereignisschleife stecken bleiben (bei der die Aktualisierung des Ereignisses dazu führt, dass ein anderes Ereignis ausgelöst wird).

Ich wollte das in einen Kommentar einfügen, aber es wurde ziemlich lang ...

Jeff
quelle
2

emberjsUnterstützt tatsächlich die bidirektionale Bindung, die eine der leistungsstärksten Funktionen für ein Javascript-MVC-Framework ist. Sie können überprüfen, wo es bindingin der Bedienungsanleitung erwähnt wird.

Für emberjs müssen Sie eine bidirektionale Bindung erstellen, indem Sie eine neue Eigenschaft mit der Zeichenfolge Bindung am Ende erstellen und dann einen Pfad aus dem globalen Bereich angeben:

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 über den Aufwand für die Synchronisierung von Bindungen Gedanken machen zu müssen, wenn Werte vorübergehend sind.

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

weia design
quelle
1

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

Ich habe eine angenehme Erfahrung mit diesem Modellbinder 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 auf Github

Daniel
quelle