Ultrashock Tutorials > Flash MX 2004 > Data Binding  
 
by Peter Hall, PeterJoel.com
Download Source Files (1,5MB)  
 
Data Binding
 
- discuss this tutorial -

In the beginning...

In the beginning God created the heavens and the Earth. Now the Earth was formless and ark, so God created Flash and he saw that it was good. That was the first day. By the fourth day, God was sick of just plain old animation, so he introduced ActionScript. Day 5 God basically scrapped the old ActionScript and started again, but made it a bit more standards compliant. On the sixth day, it got a revamp and God created a component to inhabit the land. Then God saw that the component was lonely and so he created FireFly, through which components may be bound together and share all the joys of data integration. On the seventh day, God was going to rest but instead made Flash even better by fully integrating Data Binding into the authoring environment and sprucing up the component architecture.

So, what is Data Binding?

As you probably picked up, Data Binding is not new to Flash, but it has been greatly improved since it was an add-on to Flash MX. Put simply, Data Binding is an easy way to tie all your data together, without any hard work. You can match up properties of different user interface components or even link them to the data on your server via the Data components. Data Binding takes away the need to understand complex ActionScript or how to manipulate XML and reduces it to simple clicks. Data Binding is a key feature of RAD (Rapid Application Development) and is a great tool for prototyping.

The point-and-click Data Binding actually works by utilising a runtime Data Binding API. You can access this with your scripts too, provided that you include the required assets in your movie. This just involves copying the Data Binding Classes symbol from the Classes common library, which can be found in the Flash menu bar in Window -> Other Panels -> Common Libraries -> Classes . This is the best approach if you need to build binding into dynamically attached content or if you just like to work in code. However, I will be focusing on the visual interface.

Before we begin, grab the source files here and unzip them into a new directory.

Finding your bearings

To start off, let's look at the new panels, that are used for Data binding. They are a bit scary at first, but we'll soon fix that. I have placed them in order of scariness, starting with the Components Panel and ending with the Schema tab in the Components Inspector. Don't freak out just yet.


Components Panel


Component Inspector: Parameters Tab


Component Inspector: Bindings Tab


Component Inspector: Schema Tab

Basics

So, since the Components Panel is the least scary, let's start there. We're going to create a very simple binding between two CheckBoxes, like this:

(CheckBoxes.fla)

Click either of the checkBoxes and you will see that the other changes to reflect the same change. Here's how we're going to do it.

  1. Drag two CheckBoxes from the Components Panel and name them checkBox1 and checkBox2.

  2. Open the Bindings Tab in the Components Panel, and then select checkBox1. The panel should be blank because we haven't set any bindings up yet.

  3. Click the button and the Add Binding window appears.

  4. We are going to bind the selected property of the checkBox, so click on the property named "selected" and then click OK.



  5. A new binding should have appeared under the Bindings Tab. Now we need to connect it to something else. Click the field, labeled"bound to" and then complete the binding by choosing the "selected" property of checkBox2, when the window opens, as shown.





  6. And that's it! Test your movie and see the magic! If you got stuck, the FLA is named CheckBoxes.fla

Ok, so that was nice, but not exactly something you've been desperate to be able to do. And there's one panel we haven't looked at yet. The scariest one of all, the Schema Tab. The schema of a component is just an outline of how its data is structured. In the case of a CheckBox, this is very simple; by default it's just a single property, which determines whether it is selected or not. You will see that "selected" is listed in there for the checkBoxes we created just now.

Schema

Using the schema panel, we don't have to be limited to defaults. We can add new properties here and they will become available to be bound to. Often this won't do much because the property won't mean anything, but you can actually set up most component properties for binding.

As another simple example, we are going to bind the same checkBoxes together, but this time bind the selected property of one to the enabled property of the other. See the result here.

(CheckBoxes_enabled.fla)

Notice that checking and un-checking checkBox1 enables and disables checkBox2. This is getting more useful. You can use this to enable or disable parts of a form according to the user's choices. Here's how we do it.

  1. Remove the binding that we had before, by selecting either of the checkBoxes and then the Bindings Tab and click the button.

  2. Now select checkBox2, click the Schema Tab and then to add a new property.

  3. There now appears to be a lot of information to fill in in the panel beneath. But don't worry, most of it isn't needed for this. Just set the field name to "enabled" and the data type to Boolean.



  4. Now set up the binding as we did before. But this time, bind checkBox1's enabled property to checkBox2's selected property. Test, and congratulate yourself.

Is everything based on XML these days?

Yes! So get used to it - or perish! But XML doesn't have to be difficult with Data Binding. Next we are going to import an XML schema and then populate a Menu Bar from an external XML file, using the XMLConnector component.

The first thing you should know about the MenuBar component, in fact many of the XML-driven components (Menu, MenuBar, Tree), is that the names of the XML nodes are ignored. Only the attributes are used. Here is what the XML looks like:

<menu> 
    <menu-title label="file"> 
        <menu-item label="load" /> 
        <menu-item label="save" /> 
        <menu-item label="print" /> 
    </menu-title> 
    <menu-title label="edit"> 
        <menu-item label="cut" /> 
        <menu-item label="copy" /> 
        <menu-item label="paste" /> 
        <menu-item label="sub-menu"> 
            <menu-item label="nothing here" /> 
        </menu-item> 
    </menu-title> 
</menu> 

(xmlMenu.fla)

This is where the Schema Panel really comes into its own. We are going to load the data with the XMLConnector component, but use a schema to tell the menu which part of the XML to use.

  1. First of all, we need a MenuBar and XMLConnector instance on stage. I just named them menuBar and xmlConnector. You can put the XMLConnector anywhere on stage because it will be invisible when published.

  2. Next, we need to set up the XMLConnector to load the data. To do this, just fill in the details in the Component Parameters panels, as shown.



    menu.xml is the name of our XML file. Notice I set the direction to receive only, because this is a static XML document.

  3. Next is the clever bit. We use the schema panel to tell the XMLConnector what type of XML it is to expect. Make sure the XMLConnector is selected and then open the Schema Tab in the Component Inspector.

  4. Select the "results" property under the schema tab, because that is where the data will get loaded. Click the button to import a schema. Navigate to the file menu.xml and choose "Open". Your schema panel should now look like this:



    All of that information is an interpretation of the structure of your XML. Flash has noticed repeated elements and treats those as Arrays. Flash also spots values like "true" or "1" and will treat them as Booleans or Numbers accordingly. For now we are just interested in the root node, menu.

  5. Select the menuBar and then open the Bindings Tab in the Component Inspector. The menuBar has one default bindable property, dataProvider, which it expects to be XML. Lucky that!

  6. Add a binding to the dataProvider property, as we did for the selected and enabled CheckBox properties.



    Choose the menu node. And that's the binding complete!

  7. The only thing we haven't done is tell the XML to load. We just need a tiny bit of ActionScript in the main timeline:
                 
    xmlConnector.trigger();
  8. Test your movie, and be pleasantly surprised at how easy that all was.

Arrays and Indexing

Now, a huge part of DataBinding is to do with arrays, which are used for populating list-based components such as List, DataGrid or ComboBox. As I mentioned, Flash detects repeated nodes in an XML schema and treats these as an array. To demonstrate how this works, we are going to build a simple little application, which displays a housework rota.


(selectIndex.fla)

And here is the XML that drives it.

So, where to begin?

First of all let's import our XML schema. Drop an XMLConnector on stage and import the file "chores2.xml" - make sure that you import it to the results parameter and not params . Next we are going to bind the data to the comboBox, since that is what drives the application. Notice that the XML attribute that stores the days of the week is "label". That's for convenience because that is what the comboBox expects, but normally it isn't best practice. We will look at how to use more appropriate names in the next section on Formatters.

To bind the comboBox's dataprovider to the XML source:

  1. Select the comboBox and open the Bindings Tab in the Component Inspector.

  2. Add a Binding on the dataProvider property.

  3. Click the Bound To field and navigate to the XMLConnector component. Choose the day array from the schema.

Next, we need to tie together the dataGrid and the XML. This is a bit more complicated because the whole dataProvider needs to change whenever a different day is chosen from the comboBox. If you look at the XML and how Flash has interpreted the schema, you will see that it is structured as nested arrays. Each day in the array of days contains an array of jobs. Since everything is only mentioned once in the schema, our next step is to use the schema to bind to the job array inside the nth day. You should be able to do this by yourself now; bind the dataGrid's dataProvider with the job array node in the XMLConnector's schema.

But so far we haven't said which job array to bind to - in the actual XML file, there are seven to choose from - we only bound it to the nth day, whatever that is. But Flash has a little secret for determining the value of n.

  1. Select the XMLConnector again and open the Bindings Tab.

  2. Select the Binding to the dataGrid from the job array. You should notice that a new parameter has appeared at the bottom. This parameter lets us specify which index of the day array to use. You could enter a number here, but we want it to change with the comboBox selection. Essentially, this is the same as any other bindable property, so we just bind it to comboBox:selectedIndex, as we have done with other bindings.


  3. That's it.

Formatters

Ok, so we know how to get a value from one component and put it in another. But that's not always enough. Sometimes we need the data from one component to be displayed differently in another. Other times two components have incompatible data.

We tackle this using Formatters. There are several built-in formatters you can choose from, and you can also define your own using an ActionScript 2.0 class. You choose a formatter by selecting a binding and then choosing from the list. Choose Custom Formatter to use your own class.

We'll start with the built-in ones, which are:

Boolean

Perhaps the simplest of the built-in formatters. It simply takes a Boolean value (true or false) and outputs a string. You can choose what value is represented by true and false in the formatter's options.

(Bool_formatter.fla)

Compose String

Converts fields of an object into a single string. You can combine any number of fields as well as inserting other characters. To create the string template, choose formatter options and type the string in. You can put any text in there, but anything in <> will be treated as a field. If the object has child objects (eg XML) then you can use them too by targeting them with ".". The string template for the example below looks like this: "<last>, <first> (<middle>)" .

(Compose_formatter.fla)

Date

Converts a Date to a String, using a simple template, such as "MM/DD/YYYY" . The allowed tokens are "M" (month), "D" (date), "Y" (year), "H" (hours), "N" (minutes) and "S" (seconds). You can use the formatter in reverse to turn a formatted string into a Date but, for some reason, this only works if you make the binding two-way.

(Date_formatter.fla)

Number

Very simple formatter. Let's you set the number of decimal places to display. (In this case 2dp)

(Number_formatter.fla)

Rearrange Fields

Lets you match up fields in one component's dataProvider with fields named differently in another component. Fields are paired up by listing them in the formatter options as a single string like this: "label=name;data=colour;otherField=yetAnotherField" . This is useful for doing things such as displaying data in a comboBox or List; instead of changing the labelField property of the component, you can just use a rearrange fields formatter to make the field you want appear as the label. In this example, some XML is being loaded and used to populate the comboBox and the fields are rearranged so that the name attribute is used for the label.

(Rearrange_formatter.fla)

Custom Formatter

To make a custom formatter, you need to define a very simple class. All it has are two methods, format and unformat , which take on argument of any type, and may return anything. In this example, the class formats a number into pounds sterling.
// class used to convert numbers to sterling currency and back again 
class SterlingFormatter { 
 
    // turns a number into a string 
    function format (data:Number) : String{ 
        var currency:String; 
        var pounds:Number = Math.floor(data); 
        var pence:Number = Math.round((data - pounds)*100); 
        var poundsStr:String = String(pounds); 
        var penceStr:String; 
        if(pence<10){ 
            penceStr = "0" + String(pence); 
        }else{ 
            penceStr = String(pence); 
        } 
        currency = "£" + pounds + "." + penceStr; 
        return currency; 
     } 
 
    // removes sterling format and returns a number 
    function unformat (data:String) : Number { 
        var str:String = data.substr(1); 
        var num:Number = parseFloat(str); 
        return num; 
     } 
 }


Type a number on the left to see it formatted in £ on the right.


Limitations, Precautions and Practices

Author-time Data Binding is based around movieclip paths, which brings with it a few limitations and dangers. The main problem is that, when you create a binding between two components, these component instances have to be identified uniquely and this is done by their paths. So, if you change the path of a component, after applying a binding, you will lose that binding. Although I should note that you can safely change the instance name of a component without risk to its bindings.

In general, components are resolved at runtime from absolute paths but, if you are applying bindings to a movieClip that is not on stage, the bindings will be relative to the furthest parent that can be identified. The problem here is that the same movieClip will be interpreted differently if it is edited in place on stage or if it is edited from the library. To avoid confusion, conflict and lost work, you need to follow these guidelines.

  1. Do not use bindings in a movieClip that is both added to the stage at author-time and attached dynamically.
  2. Never apply bindings after choosing to "Edit" a stage symbol. Use "Edit in Place" to preserve the movieClip's context.
  3. Plan your application carefully, before starting to add bindings, particularly if it is complicated. It would be a shame to lose all of your bindings just because you realised that all of your components should be nested in a movieClip
  4. If you need to load the application dynamically into another movie, use a _level instead of a movieclip target.

In general, the above can be achieved most simply by building your application with Forms from the outset. Create all of the screens and add components. Get the screen-flow working and then add data. The last point in the list is a bit annoying, but it isn't really a huge problem in most circumstances.

If you have looked at the source FLAs, you will notice that I have put some arrows in a guide layer. These are not so important with a simple binding, but more complex systems of bindings can be hard to track, so it is very worthwhile, as the easiest way of "documenting" what you are doing. To describe in words what you are doing with a binding is difficult, but a picture explains it in an instant. If something needs a little more explanation then a text note in a guide layer is helpful too. These arrows are not a formal notation by any means; the important thing is to leave some kind of indication of what is going on.

Conclusion

Data Binding in Flash MX Professional 2004 is a huge topic and there is a lot that I have not covered, including the runtime API and validation. It has its problems but it is well worth getting to grips with - there is so much functionality here that it is just not worth doing it all over again for yourself.

While you probably would not choose to use the Data Binding panels for an enterprise level application, you might well use the runtime API directly. The panels are great for rapid prototyping or small applications because they provide a very easy way to build complex data interaction fast. Validation and Formatting are extensible via AS2 classes so there really is no limit.

- discuss this tutorial -
 
©2003 Ultrashock.com - All rights reserved