web-dev-qa-db-ja.com

双方向バインディングとは何ですか?

Backboneは双方向バインディングを行わないことをたくさん読みましたが、この概念を正確に理解していません。

誰かがMVCコードベースで双方向バインディングがどのように機能し、Backboneではどのように機能しないかの例を教えてもらえますか?

154
Chris M

双方向バインディングとは、単に次のことを意味します。

  1. モデルのプロパティが更新されると、UIも更新されます。
  2. UI要素が更新されると、変更はモデルに反映されます。

Backboneには#2の「組み込み」実装はありません(ただし、イベントリスナーを使用して確実に実装できます)。他のフレームワーク Knockoutのように、双方向のバインディングを自動的に結び付けます


Backboneでは、ビューの「render」メソッドをモデルの「change」イベントにバインドすることで、簡単に#1を達成できます。 #2を実現するには、入力リスナーに変更リスナーを追加し、ハンドラーでmodel.setを呼び出す必要もあります。

ここにフィドルがあります バックボーンに双方向バインディングが設定されています。

222
McGarnagle

双方向バインディングとは、モデルに影響を与えるデータ関連の変更は、一致するビューに即座に伝播され、ビューで行われた変更(たとえば、ユーザー)は基礎となるモデルに即座に反映されます。アプリデータが変更されると、UIも変更され、その逆も同様です。

これは、「モデル」抽象化をアプリケーション内のあらゆる場所で使用するための安全でアトミックなデータソースにするため、Webアプリケーションを構築するための非常に堅実な概念です。ビューにバインドされたモデルが変更された場合、それに対応するUI(ビュー)の部分はそれを反映し、何があってもと言います。また、UI(ビュー)の一致部分は、アプリケーションデータを最新の状態に保つために、ユーザー入力/データを収集する手段として安全に使用できます。

優れた双方向バインディングの実装は、開発者の観点から、モデルと一部のビューとの間のこの接続をできるだけ単純にする必要があることは明らかです。

Backboneは双方向バインディングをサポートしないとは言えないuntrueです。フレームワークのコア機能ではありませんが、実行できますただし、Backboneのイベントを使用するだけです。単純な場合には、明示的なコード行がいくつか必要です。より複雑なバインディングでは非常に危険になります。以下に簡単な例を示します(テストのために、説明のためにオンザフライで記述されたコード):

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}

これは、未加工のバックボーンアプリケーションの非常に典型的なパターンです。ご覧のとおり、適切な量の(かなり標準的な)コードが必要です。

AngularJS およびその他の代替手段( EmberKnockout …)は、最初の市民機能として双方向バインディングを提供します。いくつかのDSLの下で多くのエッジケースを抽象化し、エコシステム内で双方向バインディングを統合することに最善を尽くします。この例は、AngularJSで次のようになります(テストされていないコード、上記を参照)。

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

かなり短いです!

ただし、一部の完全な双方向バインディング拡張機能は存在することに注意してくださいBackboneにも(生の、複雑さを減少させる主観的な順序): エポキシStickitModelBinder

たとえば、Epoxyの優れた点の1つは、テンプレート(DOM)またはビュー実装(JavaScript)内でバインディング(モデル属性<->ビューのDOM要素)を宣言できることです。 DOM /テンプレートに「ディレクティブ」を追加することを強く嫌う人もいます(AngularJSで必要なng- *属性や、Emberのデータバインド属性など)。

Epoxyを例にとると、生のBackboneアプリケーションを次のように作り直すことができます(…):

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}

全体として、ほとんどすべての「メインストリーム」JSフレームワークは双方向バインディングをサポートしています。 Backboneなど、それらの一部は、動作させるために追加の作業を必要としますsmoothlyが、特定の方法を強制しない最初から同じものです。だからそれは本当にあなたの心の状態についてです。

また、あなたは Flux に興味があるかもしれません。これは、円形パターンによる一方向バインディングを促進するWebアプリケーション用の異なるアーキテクチャです。データの変更時にUIコンポーネントを高速で全体的に再レン​​ダリングするという概念に基づいており、一貫性を確保し、コード/データフローについての推論を容易にします。同じ傾向で、たとえば Cycle のように、MVI(Model-View-Intent)の概念を確認することもできます。

43
chikamichi

McGarnagleには素晴らしい答えがあり、あなたは彼を受け入れたいと思うでしょうが、データバインディングがどのように機能するかについて(あなたが尋ねたので)言及したいと思いました。

通常、データに変更が加えられるたびにイベントが発生し、リスナー(UIなど)が更新されることで実装されます。

双方向バインディングは、これを2回実行することで機能します。イベントループ(イベントからの更新によって別のイベントが発生する)に巻き込まれないように、少し注意を払っています。

これをコメントに入れるつもりだったが、かなり長くなっていた...

23
Jeff

実際に emberjs は双方向バインディングをサポートします。これは、javascript MVCフレームワークの最も強力な機能の1つです。ユーザーガイドで binding に言及している箇所を確認できます。

emberjsの場合、双方向バインディングを作成するには、最後に文字列Bindingを持つ新しいプロパティを作成し、グローバルスコープからパスを指定します。

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

バインディングはすぐには更新されないことに注意してください。 Emberは、変更を同期する前にすべてのアプリケーションコードの実行が完了するまで待機するため、値が一時的な場合にバインドを同期するオーバーヘッドを心配することなく、バインドプロパティを何度でも変更できます。

選択した元の回答の延長に役立つことを願っています。

1
weia design

双方向バインディングを提供し、本当にうまくプレイする多くの異なるソリューションがあることに言及する価値があります。

このモデルバインダーで楽しい経験をしました- https://github.com/theironcook/Backbone.ModelBinder 。賢明なデフォルトを提供しますが、モデル属性から入力要素への多くのカスタムjqueryセレクターマッピングを提供します。

github には、バックボーンの拡張機能/プラグインの拡張リストがあります。

0
Daniel