Data Binding for Flash
I was talking to my parents on the phone last Sunday as I do most Sundays, and my dad said that he had never read my blog until just a few days ago. He was impressed, he said, because he had absolutely no idea what I was talking about. "It's like another language from another planet." Granted, the things I often write about are usually the most arcane and technical things I do. But, I think it's time to bring it down a notch and write about the simple things that make writing code for Flash more enjoyable. For me, one of the nicest is data binding. This post is an introduction to the concept of storing application state in a Model Locator and using my BindableModel as a way to bind that data to view components.
Let's imagine we are creating a Flash movie, hereafter referred to as our "app", short for "application", because we are programmers after all. In my app I have three MovieClips (aka "views"). One is the menu that allows me to choose which section to display. Another is the section content that gets displayed. I also have a set of arrow buttons that allow me to go forward and back through the sections. So, we need code to highlight and dim the section buttons. We need code to enable and disable the forward and back buttons, and we need a way to tell the content viewer what section we are on. When I click a menu button, I want the content to change, and I want the menu to show which section I am now on. When I click an arrow button, I want the content to change, and again want the menu to show which section I am now on.
The redundancy in that last sentence is exactly what we want to avoid with our code. We want things clean and simple. This is our goal, and the first step down the road to clean code is separating out pieces of code and data that will be used in more than one place. In our case, this is pretty simple. We have one piece of data. It is a number that represents what section we are on. So that we can keep all of our views in sync, we are going to store this number somewhere everyone can see it. And, since we will most likely have more data to keep track of as we move along, we are going to put it inside of an object that we will call "model", because that's a good name for a data holder, right. This is the basics of what some call a Model Locator.
-
model.section = 1; // looks like we are on section one
When a section button is clicked, we update the model. When an arrow button is clicked we update the model. Our job is half done, and now we just need to update our views (the user interface). We want to make it so that anytime the model is changed, our views are notified. Yes, we could write code somewhere next to our section button that loads an image into our content viewer. And, we could copy and paste similar code into the arrow buttons. But, we'd also have to hack in all kinds of code to update button states, and you can see how messy that would get.
Now, what if every view was responsible for updating itself, and all it needed to know was what section we were on? Each button could automatically highlight or dim itself accordingly without any master controller. The content viewer could autonomously show the section. What we need is a way for the Model to notify the Views whenever it is changed. What would be super nice is if we could somehow link the value in the model to a copy of that value in each view. This is data binding.
If you have looked at the MXML that makes up Flex apps, you may have seen something like this.
-
<Menu selectedIndex="{model.section}" />
There we are "binding" the section property of the model to the 'selectedIndex' property of the menu. There would of course be other markup and such, but we are talking Flash now, not Flex. So, without MXML, we need a way to do this with actionscript. Maybe something like this...
-
model.bind( 'section', myMenu, 'selectedIndex' );
The problem is that there is no data binding built into Flash. This is not really magic. We just need to make the properties on our Model getters and setters and put logic in there that dispatches custom events whenever the value changes. I have a BindableModel class that does exactly this, and I made it so you don't have to mess with events at all. First you need to get my code library from http://bumpslide.googlecode.com/. Download the latest version (bumpslide_as3_XXXX.zip under featured downloads), unzip, and put the 'com' folder in the same directory as your FLA file.
Now, we will have to actually write some code. This class is a Singleton that extends com.bumpslide.data.BindableModel:
-
package {
-
import com.bumpslide.data.BindableModel;
-
-
/**
-
* Stores application state and dispatches events when values change
-
*
-
* View components can bind to these properties
-
*
-
* @see com.bumpslide.data.Binding
-
* @see com.bumpslide.data.BindableModel
-
*
-
* @author David Knape
-
*/
-
public class Model extends BindableModel {
-
-
//--------------------------
-
// Singleton Implementation
-
//--------------------------
-
-
static private var instance:Model;
-
-
public static function getInstance():Model {
-
if(instance == null) instance = new Model(new PrivateConstructor());
-
return instance;
-
}
-
-
function Model(priv:PrivateConstructor) {
-
// set defaults here
-
section = 1;
-
}
-
-
//--------------------------
-
// Bindable Properties
-
//--------------------------
-
-
public function get section():uint {
-
return get('section');
-
}
-
-
public function set section( v:uint ):void {
-
set('section', v);
-
}
-
}
-
}
-
class PrivateConstructor {}
The BindableModel base class gives us some special methods named 'get' and 'set'. (you would think that wouldn't be allowed, right?) These methods store a copy of the variable behind the scenes so that it can be checked if and when it changes. If it is changed, then a change event is fired. By creating getters and setters for each bindable value, we now have a rather transparent way of affecting application state from elsewhere in the application.
For instance, anywhere in the app, I could write:
-
var model:Model = Model.getInstance();
-
model.section = 1;
And, even better, I can setup a binding like this:
-
model.bind( 'section', this, handleSectionChange);
-
// or
-
model.bind( 'section', this, 'sectionNum');
The first option calls the handleSectionChange function whenever the section changes. The second one will bind directly to the sectionNum property of the current class.
To see this in action, take a look at the SectionButton.as class from the Bumpslide App Template. The variable names are a little different, but you can get the idea.
While you're at it, you may want to take a look at my app template. It's just a simple starting point for creating an app in Flash and it includes a BindableModel implementation that you may be able to use right out of the box.
Under the hood, this works very much like data binding in Flex. The BindableModel class dispatches a kind of property change event (com.bumpslide.events.ModelChangeEvent), and bindings (instances of com.bumpslide.data.Binding) are really just wrappers around event listeners that fire off your callback methods or setters as needed. Because this is just a particular kind of event, you can have things such as view components also support binding by just dispatching that event. For instance, my ComboBox component dispatches change events for selectedItem and selectedIndex properties, and I've added the bind and unbind methods to the base Component class, so you can now write code like this...
-
myComboBox.bind( 'selectedItem', myTextField, 'text' );
For the record, this is not Model-View-Controller since we don't have a controller. But, for simple apps, this is often enough. You can insert logic into your model's setters to implement light weight business logic. However, if you want to go in the direction of the Command pattern, I have a nice Cairngorm-esque FrontController and Command implementation that works in Flash and even has support for callbacks that work very much like those in the UM Cairngorm extensions. In this scenario, my BindableModel becomes the missing piece that prevented you from using something like Cairngorm in Flash. But, that really is another topic. An App Template with support for commands is coming soon.
If you have any questions, post them on the new Bumpslide mailing list, or look me up on twitter.
Remember, latest code is always in the SVN trunk.
Tags: as3, databinding, mvc

March 4th, 2009 at 1:12 pm
quick note for the nerds: this is one-way, weak-referenced binding. But, unbinding when you're done is still considered best practice.
March 4th, 2009 at 2:08 pm
excellent post. looking forward to trying it out.
March 4th, 2009 at 2:49 pm
thanks david, this looks rad! can't wait to give it a try.
March 5th, 2009 at 9:45 am
impressive!
March 5th, 2009 at 4:17 pm
We implemented this approach (even utilizing bumpslide), though slightly different, on the burton website. (in all fairness I should give that credit to Phong, I jumped on that project late in the game) It was my first approach at using bindable models, and it was a glorious revolution. Kudos. Nice to meet you the other night, BTW.
March 6th, 2009 at 1:48 am
good way to explain the databinding. nice approach for beginner.
thx
S.
March 6th, 2009 at 1:53 pm
You know you could just use the Flex Binding classes in Flash.
March 6th, 2009 at 2:14 pm
tink: Your point is definitely valid now that you can use Flex SWC's from within CS4, but this is code that I've been using for quite awhile before that was possible. I'm documenting it now, because a number of people asked me to do so. There are a lot of Flash developers that don't want to mess with the Flex framework and the overhead that comes with it. This is clearly not as robust as the binding classes in Flex, and it's not intended as a replacement for them. If you do want to go the route of using Flex binding in a Flash project, I would recommend checking out the Flight framework binding classes. They provide a lighter-weight wrapper around ChangeWatcher that doesn't have so many dependencies as the standard binding utils.
March 7th, 2009 at 6:02 am
Thanks for the response.
Personally I wouldn't ever code and compile in Flash, when i refer to Flash I basically mean an AS 3.0 Project, which you've been able to use the Flex databinding in for sometime.
For me the Flash IDE is a tool for creating graphical assets and animations.
Do you know the size of the overhead that come with the Flex databinding classes? I would presume its pretty small.
March 7th, 2009 at 1:40 pm
Tink, the flex compiler itself is, in my opinion, the best part of the flex sdk. I use it all the time, and I agree wholeheartedly with your sentiment. I definitely don't code in Flash, but I often work with clients and other developers that expect to be able to just open an FLA file and publish. I don't have any numbers on the flex databinding classes. I do know that the flight framework guys went out of their way to reduce the number of framework classes required to use a convenient set of binding utils with as3-only projects. I also know that when I first moved to AS3, I spent a solid week trying to make use of ChangeWatcher in projects compiled from Flash before porting my AS2 data binding code to AS3. At that time, I dramatically changed my approach to binding, so I guess I can't really call it a port.
Anyway, Tink, I'm a fan of your work, and I read your blog, so I greatly appreciate your feedback. Thanks.
March 12th, 2009 at 9:19 am
Thanks David. I feel, at least, a little bit more enlightened.
April 26th, 2009 at 3:27 am
great post! But i am with tink. To use the Binding stuff from the flex sdk will not generate an overhead. If you use BindingUtils or ChangeWatcher directly there are no external dependencies to the framework. And performance is pretty good.
May 13th, 2009 at 10:05 am
Really cool tutorial, thanks.
@tink - would be good if you could write that up in a tutorial