Categories

Recent Entries

Syndicate

2

Cairngorm - 1 Data Binding

In my introduction to Cairngorm I covered a list of features that I have found very handy. One of the most useful, and easiest to understand, is Cairngorm’s ability to maintain application state. Before adopting Cairngorm, I found myself passing data all over my applications. Not only was it hard to track down bugs, it made the application tightly bound. Cairngorm uses a singleton to keep application state. This is achieved though an empty interface called ModelLocator. Empty Interface? Yes, that’s right, it’s an empty interface that isn’t referenced anywhere. At first I was puzzled by this, and left it out of my code. After several projects, I decided to add the ModelLocator reference back into my classes. Although it is useless and not needed, it does let you know right away that the class is a singleton.

A bit of a tangent, but worth covering: You might notice is that the constructor is public. ActionScript doesn’t allow for any constructor modifier other than “public.” Also the class throws an error if the constructor is called more than once. In fact, you should never call the constructor. Always use the getInstance() method. This ensures that the constructor is only called on time.

The following example demonstrates passing data via bindings as well as using the ModelLocator. As I mentioned before, the bindings method forces your application to be tightly bound and that is a bad thing.

When using the bindings method to pass data, you assign the listData Array to the listData parameter in your AngryBindingPanelL1:

// Tutorial_1_Bindings.mxml

<AngryBindingPanelL1 listData="{listData}" />

The parameter listData is declared in AngryBindingPanelL1 as a public bindable property:

// AngryBindingPanelL1.mxml

[Bindable] public var listData : Array;

Then this data is passed to the AngryBindingPanelL2 class. Yet another bindable property. As you can see, these bindable variables are just conduits for data. The classes declaring them don’t use them, and the classes’ knowledge of their children is a bit suspect, causing the application to become tightly bound:

// AngryBindingPanelL1.mxml

<containers:AngryBindingPanelL2 listData="{listData}" />

My apologies for showing you this again, but this is the code found in AngryBindingPanelL2. If you think it looks like what is in AngryBindingPanelL1, that’s because it does:

// AngryBindingPanelL2.mxml

[Bindable] public var listData : Array;

Lastly in order to get our data to the menu, we just bind it to the ComboBox:

// AngryBindingPanelL2.mxml

<mx:ComboBox dataProvider="{ listData }" labelField="title" />

In case you weren’t able to follow all that, there is a binding chain that looks like the following Application.listData -> AngryBindingPanelL1.listData -> AngryBindingPanelL2.listData -> ComboBox.dataProvider. We had to add a listData parameter in AngryBindingPanelL1 and in AngryBindingPanelL2 even though those classes never used it.

Now let’s see what the ModelLocator method brings to the table. There is an additional step in the Application, we set the data in the model. Later you will see us setting data from anywhere we want, but for this example we are going to set the data in the init function. This is the same Array from before, but this time it has the init function below it:

Instead of passing the listData to the AngryBindingPanelL1, and then the AngryBindingPanelL2, we are simply setting the data in the init function and forgetting about it. This is nice because it frees you to set and get data where it is relevant in the application, and keep classes not involved with the data out of the mix. Our data is set so now all we have to do is access it in the right spot. In our case that spot is the dataProvider on the ComboBox: