javascript - What is two way binding?

ID : 20431

viewed : 29

Tags : javascriptdata-bindingbackbone.jsjavascript

Top 5 Answer for javascript - What is two way binding?

vote vote


Two-way binding just means that:

  1. When properties in the model get updated, so does the UI.
  2. When UI elements get updated, the changes get propagated back to the model.

Backbone doesn't have a "baked-in" implementation of #2 (although you can certainly do it using event listeners). Other frameworks like Knockout do wire up two-way binding automagically.

enter image description here

In Backbone, you can easily achieve #1 by binding a view's "render" method to its model's "change" event. To achieve #2, you need to also add a change listener to the input element, and call model.set in the handler.

Here's a Fiddle with two-way binding set up in Backbone.

vote vote


Two-way binding means that any data-related changes affecting the model are immediately propagated to the matching view(s), and that any changes made in the view(s) (say, by the user) are immediately reflected in the underlying model. When app data changes, so does the UI, and conversely.

This is a very solid concept to build a web application on top of, because it makes the "Model" abstraction a safe, atomic data source to use everywhere within the application. Say, if a model, bound to a view, changes, then its matching piece of UI (the view) will reflect that, no matter what. And the matching piece of UI (the view) can safely be used as a mean of collecting user inputs/data, so as to maintain the application data up-to-date.

A good two-way binding implementation should obviously make this connection between a model and some view(s) as simple as possible, from a developper point of view.

It is then quite untrue to say that Backbone does not support two-way binding: while not a core feature of the framework, it can be performed quite simply using Backbone's Events though. It costs a few explicit lines of code for the simple cases; and can become quite hazardous for more complex bindings. Here is a simple case (untested code, written on the fly just for the sake of illustration):

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} 

This is a pretty typical pattern in a raw Backbone application. As one can see, it requires a decent amount of (pretty standard) code.

AngularJS and some other alternatives (Ember, Knockout…) provide two-way binding as a first-citizen feature. They abstract many edge-cases under some DSL, and do their best at integrating two-way binding within their ecosystem. Our example would look something like this with AngularJS (untested code, see above):

<div ng-app="app" ng-controller="MainCtrl">   Edit the data:   <input name="" ng-model=""> </div> 
angular.module('app', [])   .controller 'MainCtrl', ($scope) ->     $scope.mymodel = {data: ''} 

Rather short!

But, be aware that some fully-fledged two-way binding extensions do exist for Backbone as well (in raw, subjective order of decreasing complexity): Epoxy, Stickit, ModelBinder

One cool thing with Epoxy, for instance, is that it allows you to declare your bindings (model attributes <-> view's DOM element) either within the template (DOM), or within the view implementation (JavaScript). Some people strongly dislike adding "directives" to the DOM/template (such as the ng-* attributes required by AngularJS, or the data-bind attributes of Ember).

Taking Epoxy as an example, one can rework the raw Backbone application into something like this (…):

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} 

All in all, pretty much all "mainstream" JS frameworks support two-way binding. Some of them, such as Backbone, do require some extra work to make it work smoothly, but those are the same which do not enforce a specific way to do it, to begin with. So it is really about your state of mind.

Also, you may be interested in Flux, a different architecture for web applications promoting one-way binding through a circular pattern. It is based on the concept of fast, holistic re-rendering of UI components upon any data change to ensure cohesiveness and make it easier to reason about the code/dataflow. In the same trend, you might want to check the concept of MVI (Model-View-Intent), for instance Cycle.

vote vote


McGarnagle has a great answer, and you'll want to be accepting his, but I thought I'd mention (since you asked) how databinding works.

It's generally implemented by firing events whenever a change is made to the data, which then causes listeners (e.g. the UI) to be updated.

Two-way binding works by doing this twice, with a bit of care taken to ensure that you don't wind up stuck in an event loop (where the update from the event causes another event to be fired).

I was gonna put this in a comment, but it was getting pretty long...

vote vote


Actually emberjs supports two-way binding, which is one of the most powerful feature for a javascript MVC framework. You can check it out where it mentioning binding in its user guide.

for emberjs, to create two way binding is by creating a new property with the string Binding at the end, then specifying a path from the global scope:

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 

Note that bindings don't update immediately. Ember waits until all of your application code has finished running before synchronizing changes, so you can change a bound property as many times as you'd like without worrying about the overhead of syncing bindings when values are transient.

Hope it helps in extend of original answer selected.

vote vote


Worth mentioning that there are many different solutions which offer two way binding and play really nicely.

I have had a pleasant experience with this model binder - which gives sensible defaults yet a lot of custom jquery selector mapping of model attributes to input elements.

There is a more extended list of backbone extensions/plugins on github

Top 3 video Explaining javascript - What is two way binding?