What Flex taught me about data-binding

August 10th, 2010 · 21 Comments ·

Like most other developers, when I first came across the Flex data-binding, I thought of it as an interesting feature, but haven’t realized the true implications of it until much later. Data-binding in Flex has revolutionized the way I think about building UIs.

To understand why data-binding is so revolutionary, let’s look at standard Model-View-Controller setup for building UIs.

Login
Login Failed

Let’s start off with a model. A model is simply an object which has properties for all of information we may wish to display.

Model

package example.flextesting {
  [Bindable]
  public class LoginModel {
    username:String;
    password:String;
    showError:String;
  }
}

Now, model by itself is not that interesting, as we need to add behavior. To keep separation of concerns we put all of the behavior to the controller.

Controller

package example.flextesting {
  public class LoginController {
    public var model:LoginModel;
    public var authenticator:Function;
    public function login():void {
      showError = authenticator(username, password);
    }
  }
}

Boiler plate problem

Without data-binding we have to write a lot of boiler plate code which copies the data from the model to the view. In our example this may be simple as we only have three fields to copy, but in a complex forms this may be several hundred things to copy. With time, this gets so complicated that adding a new field requires us to change many things in unison: the view, the model and and code which copies it to the view.

Circular Dependency Problem

At this point we need the view to be able to lay it out in MXML. Now imagine there is no data-binding. We have a problem, we need to notify the view to update itself from the model, and we need to get the view to call the login() function in the controller. This creates a circular dependency between the controller and the view, and there is just no way around it. This means that we can not use constructor dependency-injection.

Testing Nightmare

But there is a more serious problem, we need to test our code to make sure that it works as intended. We can easily instantiate the model, but instantiating the controller requires us to also instantiate the view. In many cases it may be impractical or impossible to instantiate the view in the test, and therefore the dependency on the view from the controller is causing the problems. The reason why it may be hard to instantiate the view is that the view may have dependency on other views and other controllers.

One way to solve this circular dependency is to create an interface for the view. That way we can have two implementations of the view. One is the real view, and second is a mock implementation of the view. In the tests we can just instantiate the mock view and we are home free. While this is a good solution it requires us to write extra interfaces and extra implementations, and so it is cumbersome. Worse, any changes to the view require us to change 4 files (controller, interface, view, and mock view). Can we do better?

Data-binding reverses dependencies

Data-binding comes to the rescue. Data-binding solves our circular problem in a very clever way. It makes it so that the controller has no reference to the view. View still recognizes the controller, as the former needs to call methods on the latter when the user interacts with it, but the circular dependency is broken. Better yet, the remaining dependency is from the view to the controller, and not the other way around. This is very important, because it allows us to test the controller in isolation: we can easily instantiate the model and the controller without pulling in the view dependency.

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox
    xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:flextesting="example.flextesting.*">
  <flextesting:LoginController id="cntl"/>
  <mx:Form>
    <mx:FormItem label="Username:">
      <mx:TextInput text="{controller.model.username}"
           change="cntl.model.username =
                       event.currentTarget.text"/>
    </mx:FormItem>
    <mx:FormItem label="Password:">
     <mx:TextInput text="{controller.model.password}"
          change="cntl.model.password =
                       event.currentTarget.text"
          displayAsPassword="true"/>
   </mx:FormItem>
   <mx:FormItem label="Label">
     <mx:HBox>
       <mx:Button label="Login"
           click="controller.login()"/>
        <mx:Label text="Login Failed"
            visible="{cntl.model.showError}"
             color="#FF0000" fontWeight="bold"/>
     </mx:HBox>
   </mx:FormItem>
 </mx:Form>
</mx:VBox>

The magic of data-binding comes from the curly brackets ‘{}’. As you can see in the MXML above, the TextInput and the Label are both controlled by the ‘{}’. The data-binding acts as a kind of reverse dependency, a property which is very welcome, as we are trying to isolate the controller.

What I want is reverse data-binding

Unfortunately, Flex has not taken the data-binding far enough. When the model changes, the View changes as well. But since the view is a TextField, we also want the model to change when the user changes the form. This revers data-binding is not available in Flex out of the box and so we have to simulate it by adding change events that copy the data back to the model. You can see this in the MXML above, the forward data-bindings are marked in yellow and the reverse are marked in blue. This creates a lot of extra code which clutters the application.

Conclusion

So what have we learned about data-binding:

  • MVC inherently suffers from circular dependencies which create problem in code, that makes unit-testing of the code very difficult.
  • Data-binding reverses the normal flow of dependencies allowing us to break up circular dependencies, and thus get a less coupled system.
  • Data-binding eliminates a lot of boiler plate code which shuttles the data from the model to the view, which makes our code easier to read and understand.

Tags: Uncategorized

21 responses so far ↓

  • Florian // Aug 10, 2010 at 9:44 am

    Hi Misko,

    The latest Flex 4 SDK adds two-way data binding as well.

  • misko // Aug 10, 2010 at 9:54 am

    @Florian,

    that is great! I did not know that.

  • sudr // Aug 10, 2010 at 10:16 am

    “MVC inherently suffers from circular dependencies which create problem in code, that makes unit-testing of the code very difficult.”

    This seems to be a sweeping incorrect statement.

    In most web MVC frameworks, the UI widgets bind to the Model via the Controller. The controller doesn’t need to know about the view. The “notify the view to update itself from the model” happens by user action or navigation.

    It would be helpful if you could provide example where the Controller is directly invoking a method call on a view and thereby has a hard dependency on the view.

  • Dilip // Aug 10, 2010 at 12:33 pm

    Microsoft’s XAML does something remarkably similar with both Silverlight based and desktop based (WPF) applications.

    The XAML infrastructure allows you to take this a bit further and dedicate a class to do just 2-way data binding with the View. The presenter (Supervising Controller variant) would take care of dealing with the model. Any action on the view will have to go through the presenter. Similarly any data that presenter receives will be updated on the databinder class and 2-way databinding will automatically take care of updating the view.

    Does this make sense?

  • Rafael de F. Ferreira // Aug 10, 2010 at 1:54 pm

    You should checkout the Flapjax javascript extension (http://www.flapjax-lang.org/). There is extensive literature on what you called “two-way data binding” under the pompous name of Functional Reactive Programming (FRP).

    Cheers.

  • blakaz // Aug 11, 2010 at 3:34 am

    as workaround (before flex 4):
    http://www.adobe.com/livedocs/flex/2/langref/mxml/model.html

    ..
    {textInput_username.text}

  • blakaz // Aug 11, 2010 at 3:36 am

    ..
    {textInput_username.text}

  • blakaz // Aug 11, 2010 at 3:37 am

    :) don’t know how use mx-tags

  • Masklinn // Aug 11, 2010 at 5:11 am

    Misko, you should check out Obj-C and Cocoa, it’s chock-full of that kind of stuff from ground up.

    See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/WhatAreBindings.html for instance.

  • misko // Aug 11, 2010 at 8:01 am

    @Masklinn, love the objective part, not so much the C part.

  • misko // Aug 11, 2010 at 8:04 am

    @sudr,

    we are not talking html web frameworks, we are talking about rich client side apps, and those have slightly different rules.

  • Phillip // Aug 19, 2010 at 6:36 am

    Misko,

    I suggest you take a look at “MVVM” Model-View-ViewModel, it is a variation on the MVP & MVC methodologies that leverages data binding for creating a highly testable model representing the view seperate the specific UI controls (hence ViewModel). A lot of what is out there is geared more specifically to WPF and Silverlight, but the concepts and goals are aligned with what you are investigating here.

    Just a thought, thanks for the great blog!

  • Bob // Aug 20, 2010 at 2:21 am

    Hey, I’ve noticed that your RSS feed doesn’t work, both on FF and IE.

  • Lee Campbell // Aug 24, 2010 at 9:36 am

    In WPF (and Silverlight 4) you can further seperate the dependencies by the use of DataTemplates instead of a view. This allows you to just “Show” your ViewModel and the WPF binding engine will understand that the Type should be templated by the DataTemplate. Very nice for testing.

  • Parag Shah // Sep 1, 2010 at 9:05 pm

    Hi Misko,

    NIce blog post. I agree that MVC can create circular dependencies, because I have been in a project where we had circular dependencies in our MVC.

    Mocking may be a solution to inject the view, when it is not possible to create it in a test scenario. If we use a library such as EasyMock, we may not have to create an Interface for the view and a mock implementation.

    The view and the controller can also be decoupled using events, where the view registers itself for ModelChangedEvent in the model (by getting the model from the controller).

    But nevertheless, I do agree that data binding is a very desired feature, as is reverse data binding.

  • Karl Böhlmark // Sep 14, 2010 at 3:24 am

    Yeah databinding is nice, but I can’t believe it has taken so long for web developers to figure this out. This has been a standard part of .net winforms development for ages and probably in java swing land for about as long.

    It’s no wonder this is the first thing microsoft tries to bring to jQuery, after adopting it as the standard js lib.( http://github.com/nje )

  • ktutnik // Oct 5, 2010 at 3:33 am

    When talking about binding you should take a look at WPF, not as simple as Flex but it was more powerfull.

    - Support for One Way, Two Way and One Way to Source.
    - Binding source update can be specified (on Property Changed, On Lost Focust etc)
    - You can specify Converter for your binding. For example if the Controller property is Boolean and you bind it in TextBox text it will not match. Thats the converter work.

    Sorry,, maybe you knew more about this.. I just want to compare it with Flex binding.

    and i will be glad to see all this feature on angular. :)

  • Sunil // Feb 7, 2012 at 1:28 am

    Thanks for sharing this info. More informative

  • suhasini // Feb 20, 2012 at 9:54 am

    Great stuff,thanks for sharing.

  • Staev // Jun 1, 2012 at 4:13 am

    There were two replies about WPF and SL, which does not explain exactly their power. These two technologies are prepared for MVVM pattern (Model-ViewModel-View, similiar to MVC). In this pattern Model is totally hidden from View, View communicate ONLY with ViewModel. The binding betwenn ViewModel and View is possible because INotifyPropertyChanged interface. With this scenario you can create more testable code.

  • Arindam Biswas // May 22, 2013 at 5:23 am

    And misko then decided to go the angular way! :) Thanks!