Data Binding in Flex
The Flex 2 framework provides a very robust structure built to maximize the facilitation of component-driven architectures. One such aspect being a constant collaboration of data from component to component and from component to a centralized data model.
In a more traditional architecture, an implementation of a framework such as
MVC (model-view-controller) would suffice to keep components isolated from the common data. In a nutshell, the
model would contain the application data and logic and act as independent core of the system, and the
views and
controllers would be be the outlying UI elements that mediate between various input/output channels (keyboard, mouse, server, etc. for input, monitor, printer, speakers, etc. for output), each other, and the model itself. In this form, the views and controllers are typically tailored to the behavior of the model, in order to make these elements interchangeable and adaptable to the application's contrastingly solidified backbone
Introduction to Data Binding
Data binding is the preferred choice for sharing data between various classes. With data binding, any time the value of a source property is changed, the value is automatically updated for the destination property as well. This makes it easy to keep all your components synced, and to seamlessly add or remove components at any time within the system. Also, since components within the Flex 2 framework are created asynchronously, data binding ensures that the values for those components will be accurately assigned once its initialization is complete. In Flex, there are various different ways to set up data binding, depending on what you're trying to achieve.
Data Binding in MXML
MXML is great for setting up an application very quickly, and just the same, it's the fastest way to rig up a data binding system between MXML components. There are two ways to set up bindings through MXML: inline scripts and the
<mx:Binding> tag.
First, lets look at binding through inline scripts. Set up a new Flex Project labeled "BindingDemo" and insert the following code into
BindingDemo.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" horizontalAlign="center">
<mx:TextArea width="200"/>
<mx:ComboBox width="200"/>
</mx:Application>
Nothing too interesting to see yet. We now have a text component and a combo box now, but neither of which contain any data. Let's set up the combo box first:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" horizontalAlign="center"
initialize="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var fruitlist:ArrayCollection;
private function init():void{
fruitlist = new ArrayCollection(['Apple', 'Pear', 'Banana', 'Strawberry']);
}
]]>
</mx:Script>
<mx:TextArea width="200"/>
<mx:ComboBox width="200"
dataProvider="{fruitlist}"/>
</mx:Application>
In the code above, we've added three major pieces of code to our application. First, we inserted a
<mx:Script> tag and populated it with a variable and a function. For those of you new to Flex, the script tag allows you to inject ActionScript 3.0 code into your mxml files. The variables and functions defined in the script tag become properties and methods that are scoped to the mxml file. This allows us to set up the second part. You'll also notice a
[Bindable] meta-tag above our
fruitlist property. This is interpreted by the mxmlc compiler to prepare the property for data binding (both as a source and as a destination), and is necessary for the third part of our set-up.
The [Bindable] tag is applied to the proceeding property or getter/setter pair. If using a getters and setters, it's important to note that both the getter and the setter must be present for the corresponding property, or else data binding will not function properly. If a class declaration proceeds the [Bindable] tag, then all properties and getter/setter pairs of that class will become bindable.
In the second part, we arrange for
init() to be called by the
initialize event in the application. In MXML, events can be treated as attributes to MXML nodes. Event attributes require a method handler reference in order to be properly used. When initializing properties, you would typically create a method within a script tag to assign to the application's initialize event.
Finally, we use an inline script to bind
fruitlist to the combo box's
dataProvider. Many list controls have a dataProvider property, which should be populated with a list of values or objects of values. The list should exist as either an
ArrayCollection or
XMLListCollection, however arrays and XML objects can be accepted and internally converted to their respective "Collection" forms by the list control. Also note the use of {}'s around the bindable property. This tells the compiler that the value applied is interpretive, as opposed to literal. In other words,
dataProvider="fruitlist" would set the value of the dataProvider to the string
fruitlist, rather than the array collection referenced by
fruitlist. When the interpretive value is a bindable property, data-binding is automatically applied.
If you run a test, you can see that the combo box is now populated, however changing its value has no visible effect. To make it a little more interesting, let's add a little bit more code:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" horizontalAlign="center"
initialize="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var fruitlist:ArrayCollection;
private function init():void{
fruitlist = new ArrayCollection(['Apple', 'Pear',
'Banana', 'Strawberry']);
}
]]>
</mx:Script>
<mx:TextArea width="200"
text="My Favorite Fruit is:
{fruitComboBox.selectedItem}"/>
<mx:ComboBox
id="fruitComboBox" width="200"
dataProvider="{fruitlist}"/>
</mx:Application>
The id attribute of an mxml component is the equivalent to assigning that component to a defined property value. In other words, we can now access our combo box via
fruitComboBox the same way as we access our array collection via
fruitlist. This allows us to data-bind the combo box's
selectedItem property to our text area the same way we bound our array collection to the combo box's data provider. To further illustrate the difference between interpretive and literal, I also mixed the two for the text attribute, as shown above.
Testing it now, you'll see that the text area updates to reflect the selected value in the combo box.
As mentioned earlier, the alternative approach to data binding in MXML is to use the <mx:Binding> tag. This option does not gain much of an advantage over the inline style, with the exception of being a cleaner way to manage your data-binding. For example, the alternative for binding the combo box's data provider to fruitlist would look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" horizontalAlign="center"
initialize="init()">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var fruitlist:ArrayCollection;
private function init():void{
fruitlist = new ArrayCollection(['Apple', 'Pear',
'Banana', 'Strawberry']);
}
]]>
</mx:Script>
<mx:Binding source="fruitlist" destination=
"fruitComboBox.dataProvider"/>
<mx:TextArea width="200" text="My Favorite Fruit is:
{fruitComboBox.selectedItem}"/>
<mx:ComboBox id="fruitComboBox" width="200"/>
</mx:Application>
When working on larger MXML files, you may find that the use of binding tags may make your code much more readable, however there are a few limitations to binding tags:
- Binding tags can't mix literal and interpretive values as we could with the former approach for our text area.
- Only inline data-binding supports style attributes.