creationPolicy vs Binding

I just read a comment on an article I wrote a few years ago, creationPolicy vs. Form Data. The commenter suggested that the Save button must be able to read the values from the controls, even if those controls haven’t been created – probably to make the code easier to write or at least consistent.

I disagree with this, but after reading that article again, I see that I could have given more information to support my position.


The article suggests using a <mx:Model> to hold the data and then use data binding to transfer the information from the model to the UI controls. That’s fine for presenting the information, but it doesn’t help when you to save the information.

ActionScript 3 Approach

Here’s a different approach that works better with ActionScript 3 (for Flex 2 or Flex 3). Let’s suppose you have an Accordion with two forms: Payment Information and Shipping Address. Let’s also suppose you have two ActionScript classes that correspond to these forms: PaymentInfo and ShippingAddress. Here’s the definition of the PaymentInfo class:

// file: PaymentInfo.as
package mydata
{
[Bindable]
public class PaymentInfo
{
public var cardType:String;
public var cardNumber:String;
public var expireDate:Date;
}
}

Here’s the definition of the ShippingAddress class:

// file: ShippingAddress.as
package mydata
{
[Bindable]
public class ShippingAddress    {
public var firstName:String;
public var lastName:String;
public var street:String;
public var city:String;
public var state:String;
public var zipCode:String;
}
}

These look like ordinary ActionScript classes, but notice the [Bindable] meta tag above the class definition? That tag tells the compiler that all public properties can be used in data-binding. It is a short-cut to putting [Bindable] before each public variable.

In the Form to be used for the Payment Information you may have controls like this one to get the credit card number:

<mx:TextInput id="creditCardNumber" />

Since you want the PaymentInfo’s cardNumber property to appear in the TextInput, you can use data-binding to associate the property with the field:

<mx:TextInput id="creditCardNumber" text="{data.cardNumber}" />

That’s great for showing the credit card number if the value already exists. But how about saving that information?

Binding Tag

What you want to do is a “reverse” data-binding. Right now the {data.cardNumber} binding is one-way: whatever appears in the PaymentInfo’s cardNumber property appears in the TextInput control. What you’d like is that if you change the value in the UI control to be automatically copied back into the PaymentInfo.

You can do this by using the <mx:Binding> tag. Here’s how to do that for the card number:

<mx:Binding source="creditCardNumber.text" destination="data.cardNumber" />

Any change made to the text property of the creditCardNumber TextInput control is reflected back to the cardNumber property of the PaymentInfo class instance for this Form.

Note: You can also do this type of binding in ActionScript using the mx.binding.utils.BindingUtils class.

Example

Picture this: the Payment Information form appears (blank). You fill in the fields and pick Save. The Save button’s code does not have to access the UI controls at all: it saves the contents of the PaymentInfo class because the Binding took care of transferring the data from the control back to the data class.

<mx:Script><![CDATA[
[Bindable] private var payment:PaymentInfo; // remember to create an instance using the new operator
[Bindable] private var shipping:ShippingAddress; // remember to create an instance using the new operator
]]></mx:Script>

<mx:Accordion>
<forms:PaymentInfoForm data="{payment}" />
<forms:ShippingForm data="{shipping}" />
</mx:Accordion>

Now suppose the Shipping Address were used in the same way, but in this case, the user never opened that form. Since the Save button code is not accessing any of the UI controls on the form, only the ShippingAddress properties, it doesn’t matter if the UI controls were ever created.

In the above code example, the Binding tags will transfer changes to the controls in the PaymentInfoForm to the payment variable. Changes to the controls in the ShippingForm (if created by the user visiting it in the Accordion) will likewise be transferred to the shipping variable.

The Save button code then saves the contents of the payment and shipping variables.

Summary

Using the Binding tag to “reverse” data-binding on editable controls will make your code easier to write, understand, and more reliable. You won’t have to worry if user’s never touch containers on controls like Accordion or TabNavigator. And if the user does visit a form, data binding will populate the UI controls and Binding will read them.

And yes, if you have 100 UI controls and fields you will need 100 Binding tags.