What is two way binding? What is two way binding? javascript javascript

What is two way binding?


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.


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="mymodel.data" ng-model="mymodel.data"></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.


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...