Accessibility

Flash Article

 

Binding Data Between Components Using the Data Binding Classes

Jen deHaan

Flash Authoring QE
Adobe
Jen deHaan's blog
flashthusiast.com
webvideoblogger.com

Many of you have probably discovered how useful the Bindings tab in the Component Inspector panel can be. In case you haven't, you can use the Bindings tab to bind data between components on the Stage. This process is briefly demonstrated in this article, and in more detail within the following articles:

I also cover data bindings in my article, Building a Tip of the Day Application (Part 2): Working with Web Services.

What you might not have tried yet is creating bindings between components using simple ActionScript instead of the Bindings tab. Adding code is often faster and more efficient than relying on the authoring environment. This article introduces you to runtime data binding, and demonstrates how to create bindings using code instead of depending on the Component Inspector and several dialog boxes.

Requirements

Flash MX 2004 or Flash MX Professional 2004

Prerequisite knowledge:

Basic knowledge of the Flash authoring environment and a basic knowledge of ActionScript.

Setting Bindings Using the Component Inspector Panel

For those of you who are unfamiliar with using the Bindings tab to create a binding between components, this brief exercise demonstrates how to create a simple binding in Flash MX Professional 2004:

  1. Create a new Flash document and name it panel.fla.
  2. Drag two TextInput component instances onto the Stage and type the instance names in_ti and out_ti into the Property inspector for each instance.
  3. Open the Library panel. Currently there should only be one item in the Library (the TextInput component).
  4. Make sure the Component Inspector panel is visible (and at its full height) and click the Bindings tab.
  5. Click the in_ti instance on the Stage and then click the plus sign (+) in the Component Inspector panel to add a binding. The Add Binding dialog box opens (see Figure 1).

    Clicking the plus sign opens the Add Binding dialog box

    Figure 1. Clicking the plus sign opens the Add Binding dialog box

    Select the text property (an excellent choice because it is the only option) and click OK to create the first half of the binding.

  6. Look in the Library again (select Window > Library). You now see a new item added: the DataBindingClasses component. This special class appears automatically when you create bindings using the Component Inspector panel. It adds the data binding classes to your document.

    Note: Later, when you create bindings using ActionScript, you still need to place a copy of this class manually into the Library.

    The binding is only partially complete at this point. Creating bindings is a two-step process. First you need to define the beginning-point for the binding, which is the in_ti TextInput component in this case. Then you need to bind that property to an endpoint, which is the out_ti component.

  7. Back in the Bindings tab of the Component Inspector, make sure you select the text property and highlight the bound-to row in the lower grid. At this point you should see a magnifying glass icon on the far right of the row.

    Click this icon to open the Bound To dialog box (see Figure 2). Select the TextInput, <out_ti> entry in the Component Path pane on the left side of the dialog box. Then select the text : String entry from the Schema Location pane on the right.

    Selecting the component path and schema location in the Bound To dialog box

    Figure 2. Selecting the component path and schema location in the Bound To dialog box

    Click OK to apply the changes and close the dialog box

  8. Select Control > Test Movie to test the Flash document in the test environment. Type some text into the in_ti text input field and click the Stage to remove focus from the component. When the component loses focus, the text is copied into the out_ti instance.

By default, the binding should be two-way. This means that if you change the text within the out_ti instance and then remove focus from that component, the updated text is copied to the in_ti instance. If you want the binding only to be one-way (text copied from in_ti to out_ti but not vice-versa), then you can change the binding's direction from in/out to out in the Bindings tab. Likewise, setting the direction to in copies the text from out_ti to in_ti (but not from in_ti to out_ti).

That is the basic way that bindings work when you create them in the Flash authoring environment. However, you might want to create bindings manually using ActionScript. But why use ActionScript at all when you can use the handy graphical interface instead? You can choose to add components to the Stage dynamically using the createClassObject() method; however, you couldn't use the Bindings tab to create a binding because the components don't exist until runtime.

Creating Bindings Using ActionScript

It's not too difficult to bind data between two components at runtime. You can do so in Flash MX 2004 or Flash MX Professional 2004. You need to remember to include the DataBindingClasses component in your document for it to work because it contains the classes you need to work with. In this brief example, you create a binding between two TextInput components using ActionScript. By replicating the previous example with ActionScript, you can see the difference between manual and runtime data binding:

  1. Create a new Flash document called panel_as.fla.
  2. Drag two copies of the TextInput component onto the Stage.
  3. Give the components the following instance names: in_ti and out_ti.
  4. Select Window > Other Panels > Common Libraries > Classes and open a new common library called Classes.fla.
  5. Drag a copy of the DataBindingClasses component into the Library panel, or drag the component onto the Stage and then delete it from the Stage. You can close the common Library after you finish.

    Tip: Deleting DataBindingClasses from the Stage leaves a copy in the Library. If you forget to delete the component from the Stage, the icon is visible at runtime.

    Note: When you created a binding using the Component Inspector in the previous example, the DataBindingClasses component was added automatically to the FLA file. When you create data bindings using ActionScript, you need to copy that class into your Library manually, as shown in this step.

  6. Insert a new layer and name it actions.
  7. Add the following ActionScript to frame 1 of the actions layer:

    var src:mx.data.binding.EndPoint = new mx.data.binding.EndPoint();
    src.component = in_ti;
    src.property = "text";
    src.event = "focusOut";
    var dest:mx.data.binding.EndPoint = new mx.data.binding.EndPoint();
    dest.component = out_ti;
    dest.property = "text";
    new mx.data.binding.Binding(src, dest);

    If you prefer the somewhat shortened version, you could import the binding classes and use the following code instead:

    import mx.data.binding.*;
    var src:EndPoint = new EndPoint();
    src.component = in_ti;
    src.property = "text";
    src.event = "focusOut";
    var dest:EndPoint = new EndPoint();
    dest.component = out_ti;
    dest.property = "text";
    new Binding(src, dest);

    This ActionScript creates two data binding endpoints, one for each component you are trying to bind. The first endpoint you create defines which component it is binding from (in_ti), which property to watch for (text), and which event will trigger the binding (focusOut). The second endpoint you create lists only the component and property (out_ti and text, respectively) which is bound to the first endpoint. Finally, you create the binding between the two endpoints when you call the constructor for the Binding class (new Binding(src, dest)).

    You don't need to use fully qualified class names (such as mx.data.binding.EndPoint) in your ActionScript, as you can see in the first code snippet. If you use the import statement at the beginning of your code, you can avoid using fully qualified names. When you import all the classes in the mx.data.binding package using * (the package includes both the EndPoint and Binding classes), you can shorten your code and directly reference the EndPoint and Binding classes.

  8. That's it! Select Control > Test Movie to test the code in the test environment. Enter some text into the in_ti text input field. After the in_ti instance loses focus (click the Stage, press the Tab key, or click the second field), any text that you input into in_ti is copied to the out_ti text field (see Figure 3).

    Entering text into in_ti and pressing Tab so the field loses focus copies the text into the second field

    Figure 3. Entering text into in_ti and pressing Tab so the field loses focus copies the text into the second field

If you want to modify the text in the out_ti text input field, your code can get a bit tricky. By default, setting up manual binding (in the first example) was a two-way connection. If you change either text field, the other text field changes as well. When you create bindings dynamically, things seem to work the opposite way: Bindings are one-way by default unless you specify otherwise, as shown in the following example.

To create a two-way binding using ActionScript, you need to make a couple of small modifications to the previous code snippets. Let's assume you used the second, shortened ActionScript snippet for this example. To create a two-way binding, you need to modify it slightly (see the highlighted code) to match the following ActionScript:

import mx.data.binding.*;
var src:EndPoint = new EndPoint();
src.component = in_ti;
src.property = "text";
src.event = "focusOut";
var dest:EndPoint = new EndPoint();
dest.component = out_ti;
dest.property = "text";
dest.event = "focusOut";
new Binding(src, dest, null, true);

The two changes you make are to define an event property for the destination EndPoint instance and define two additional parameters for the Binding constructor. You use the first parameter for advanced formatting options, so you can set that value to null or undefined. The second parameter defines whether the binding is two-way (true) or one-way (false).

You might wonder where you got the focusOut event from. That's where things get a bit tricky. You might even investigate the TextInput class and use some of the listed methods (such as change() or enter()) but still not know where focusOut event comes from. The TextInput class inherits from the UIObject and UIComponent classes. If you view the UIComponent class, which adds focus support to components, you see four additional events: focusIn, focusOut, keyDown, and keyUp. Therefore, if you want the previous example to update the value in the out_ti text input field, you can change the event from focusOut to change, and then retest the document (select Control > Test Movie). Now the second value in the in_ti text input field changes and the value for out_ti is updated.

Using Binding Classes on Other Components

Luckily you can use the Binding classes with most every V2 UI component—not just the TextInput components. Check out the following example to bind CheckBox instances and Label components at runtime using ActionScript:

  1. Create a new Flash document called checkbox_as.fla and then select Window > Other Panels > Common Libraries > Classes.
  2. Drag a copy of the DataBindingClasses class into the Library.
  3. Drag a copy of the CheckBox component onto the Stage and give it the instance name my_ch.
  4. Drag a copy of the Label component onto the Stage and give it the instance name my_lbl.
  5. Create a new layer and name it actions.
  6. Add the following ActionScript to frame 1 of the actions layer:

    var srcEndPoint:Object = {component:my_ch, property:"selected", event:"click"};
    var destEndPoint:Object = {component:my_lbl, property:"text"};
    new mx.data.binding.Binding(srcEndPoint, destEndPoint);

This time, you use objects to define the endpoints instead of creating new instances of the EndPoint class. The previous snippet creates two Objects, which act as endpoints for the binding. You then create the binding when you call the constructor for the Binding class. If you want to reduce your code (and code readability) even more, you can define the Objects inline as shown in the following snippet:

new mx.data.binding.Binding({component:my_ch, property:"selected", event:"click"}, {component:my_lbl, property:"text"});

It might reduce the readability but it also reduces the amount of typing you have to do! If you share your FLA files (or ActionScript), then you might want to use the first snippet of ActionScript instead because it is more reader-friendly.

Using Components, Bindings, and Custom Formatters

You used custom formatting options with two-way bindings in the section "Creating Bindings Using ActionScript." To illustrate better the need for some custom formatters, let's look at another example:

  1. Create a new FLA file and add the DataBindingClasses class to the Library (Window > Other Panels > Common Libraries > Classes).
  2. Drag a copy of the DateChooser component onto the Stage and give it the instance name my_dc.
  3. Drag a copy of the Label component onto the Stage and give it the instance name my_lbl.
  4. Insert a new layer and name it actions.
  5. Add the following ActionScript code to frame 1 of the actions layer:

    import mx.data.binding.*;
    var src:EndPoint = new EndPoint();
    src.component = my_dc;
    src.property = "selectedDate";
    src.event = "change";
    var dest:EndPoint = new EndPoint();
    dest.component = my_lbl;
    dest.property = "text";
    new Binding(src, dest);

    This code creates a binding between the DateChooser's selectedDate property and the text property of the Label component on the Stage. Each time you click a new date in the calendar, the selected date appears in the Label component.

  6. Save the Flash document as customformat.fla in a convenient location on your hard drive. (You will recycle it in the next exercise.)
  7. Select Control > Test Movie to test the document. Try to change the dates in the Calendar component and see the currently selected date appear in the Label component. The Label component isn't wide enough to display the entire date, so the text is cropped off.

    Close the test SWF file and return to the authoring environment. Either resize the Label component on the Stage or select the Label component and set the autoSize property to left in the Parameters tab of the Property inspector.

  8. Test the document again. Now it displays the entire date, although it is awkward and lacks formatting. Depending on your particular time zone and selected date, It might appear similar to this: Thu Nov 4 00:00:00 GMT-0800 2004

    Displaying the unformatted date in the label when you click the calendar

    Figure 4. Displaying the unformatted date in the label when you click the calendar

Even though the binding works properly and displays the selectedDate property, there's a problem: These dates aren't particularly aesthetic. Nobody wants to see time zone offsets—or even hours, minutes, and seconds. What you need is a way to format the date so it's more readable and a little less mechanical. This is when custom formatters are useful.

Formatting Data Using the CustomFormatter Class

To quote the Flash documentation:

The CustomFormatter class defines two methods, format() and unformat(), that provide the ability to transform data values from a specific data type to String, and vice-versa. By default, these methods do nothing; you must implement them in a subclass of mx.data.binding.CustomFormatter.

So the CustomFormatter class allows you to convert data types to strings and back. In this case, you want to convert the selectedDate property from the DateChooser component into a nicely formatted string when the value copies into the Label component.

The following example shows you how to create your own custom formatter, which displays the date as NOV 4, 2004 instead of displaying a default date string:

  1. Select File > New and then select ActionScript file from the General tab to create a new ActionScript (.as) file.

    Note: If you do not have Flash MX Professional, create a new text file using a simple text editor, such as Notepad or TextEdit.

  2. Enter the following code into the Script pane (or text file) and save the document as DateFormat.as:

    class DateFormat extends mx.data.binding.CustomFormatter {
    	function format(rawValue:Date):String {
    		var returnValue:String;
    		var monthName_array:Array = ["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];
    		returnValue = monthName_array[rawValue.getMonth()]+" "+rawValue.getDate()+", "+rawValue.getFullYear();
    		return returnValue;
    	}
    }

    The first bit of code defines the new class called DateFormat, which extends the CustomFormatter class in the mx.data.binding package. Before you try to locate this file in the Classes folder in Flash, remember that the binding classes are compiled in the DataBindingClasses component file, so you can't view them directly.

    The only method you use is the format() method, which converts the date instance into a custom string format. The next step is to create an array of month names so that the end result looks closer to NOV 4, 2004 rather than the default date format. As always, remember that arrays are zero-based in Flash, so if the value of rawValue.getMonth() returns 1, it's February instead of January (because January is month 0). The remainder of the code builds the custom formatted string by concatenating values and returning the returnValue string.

    There is one important catch, which rears its ugly head in the previous snippet. Because you extend a class that's located in the DataBindingClasses class and isn't readily available to Flash, you encounter the following error when you check the syntax in the previous class:

    **Error** <path to DateFormat class>\DateFormat.as: Line 1: The class 'mx.data.binding.CustomFormatter' could not be loaded.
         class DateFormat extends mx.data.binding.CustomFormatter {
    
    Total ActionScript Errors: 1 	 Reported Errors: 1

    Your code is probably fine. This problem occurs when Flash cannot locate the class; because of this, syntax checking fails.

  3. Save the DateFormat.as file and return to (or open) the document you created in the previous exercise (customformat.fla).
  4. In customformat.fla, modify the ActionScript code in frame 1 of the actions layer to match the following code:

    import mx.data.binding.*;
    var src:EndPoint = new EndPoint();
    src.component = my_dc;
    src.property = "selectedDate";
    src.event = "change";
    var dest:EndPoint = new EndPoint();
    dest.component = my_lbl;
    dest.property = "text";
    new Binding(src, dest, {cls:mx.data.formatters.Custom, settings:{classname:"DateFormat", classname_class:DateFormat}});

    This new ActionScript has a few small, but exceedingly confusing additions. This time you define a customFormatter object, which tells Flash you're using the newly created DateFormat class to format the endpoint on the binding.

    Clicking a date in the calendar now shows a formatted date

    Figure 5. Clicking a date in the calendar now shows a formatted date

Adding Components to the Stage Using ActionScript

One of the biggest advantages to using the binding classes with ActionScript is creating bindings between components that have been added to the Stage at runtime. Imagine creating your own custom class that adds the appropriate text fields to the Stage at runtime, and then validates the necessary data and adds the necessary bindings. As long as you have the components in your Library, you can add those components dynamically and create bindings using a couple extra lines of code:

  1. Create a new Flash document.
  2. Drag a ComboBox and Label component into the document Library.
  3. Insert a new layer and name it actions.
  4. Add the following code to frame 1 of the actions layer:

    import mx.data.binding.*;
    this.createClassObject(mx.controls.ComboBox, "my_cb", 1, {_x:10, _y:10});
    this.createClassObject(mx.controls.Label, "my_lbl", 2, {_x:10, _y:40});
    my_cb.addItem("JAN", 0);
    my_cb.addItem("FEB", 1);
    my_cb.addItem("MAR", 2);
    my_cb.addItem("APR", 3);
    my_cb.addItem("MAY", 4);
    my_cb.addItem("JUN", 5);
    var src:EndPoint = new EndPoint();
    src.component = my_cb;
    src.property = "value";
    src.event = "change";
    var dest:EndPoint = new EndPoint();
    dest.component = my_lbl;
    dest.property = "text";
    new Binding(src, dest);

Just as in the previous examples, the first line of ActionScript imports the classes in the mx.data.binding package so you do not need to use fully qualified paths. The next two lines of code attach the components from the document's Library to the Stage. Next you position the components on the Stage.

Finally you add data to the ComboBox instance and create the binding between the my_cb ComboBox and my_lbl Label component on the Stage. The only code that's significantly different in this example is the use of the createClassObject() method, which you use to add components to the Stage at runtime.

Where to Go from Here

Congratulations! You just completed a basic introduction to using the DataBinding classes in Flash instead of having to use the Bindings tab. You created simple bindings using both the Flash interface and the DataBindingClasses component in the Common Libraries library. You also discovered how to create a simple CustomFormatter class, which enables you to convert dates and display them in a user-friendly format. Try creating some bindings between other V2 components using ActionScript. It offers you an alternative way of working with components in your applications.

About the author

Jen deHaan was raised by wolves in the deep woods of the Canadian north. Canada's chief exports include motor vehicles (or their parts), lumber, newsprint, nonmetal materials, and wheat. One overcast day in 2004, Jen left her life as a Flash deseloper (designer/developer) in Canada to write Flash documentation and samples at Macromedia in San Francisco. Aside from her ongoing work at Adobe as an instructional designer for web and video products, Jen runs several community sites for fun, and maintains a blog at www.webvideoblogger.com and weblogs.macromedia.com/dehaan. She believes that _root tends to be evil and misses Tim Horton's coffee.