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


173

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

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

回答:


249

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

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

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


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

これは、バックボーンに双方向バインディングが設定されたフィドルです。


25
あなたがそれを見れば、答えはとても痛いほど明白です。明確な答えと例を提供するために時間を割いていただき本当にありがとうございます。
Chris M

Firebaseが付属しています... 3ウェイデータバインディング->ビュー、モデル、データベース。それはかなりすっきりしていると思いました。
Levi Fuller 2016年

簡潔で短い。+1
Karan_powered_by_RedBull

46

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

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

優れた双方向バインディング実装は、開発者の観点から、モデルといくつかのビューの間のこの接続を可能な限り単純にする必要があります。

そのため、Backboneが双方向バインディングをサポートしていないと言うのはまったく正しくありません。フレームワークのコア機能ではありませんが、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: ''}

かなり短いです!

ただし、バックボーンにもいくつかの完全な双方向バインディング拡張機能が存在することに注意してください(複雑さを減少させる生の主観的な順序):EpoxyStickitModelBinder

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

Epoxyを例にとると、未加工のバックボーンアプリケーションを次のようなものに作り直すことができます(…):

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フレームワークは、双方向バインディングをサポートしています。バックボーンなどの一部のものは、円滑に動作させるために追加の作業が必要ですが、最初は特定の方法を強制するものではありません。だからそれは本当にあなたの心の状態についてです。

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


3
多くの開発者、特にReact / Flux開発者は、双方向バインディングを大規模なアプリを構築するための安全なパターンと見なしていません。
アンディ

28

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

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

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

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


2

実際に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

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

私はこのモデルバインダー-https://github.com/theironcook/Backbone.ModelBinderで快適な経験をしました。これにより、実用的なデフォルトが提供されますが、モデル属性の入力要素へのカスタムjqueryセレクターマッピングが数多く提供されます。

githubにバックボーン拡張/プラグインのより拡張されたリストがあります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.