creationPolicy vs Form Data

This is a topic that occurs from time to time. Say you have a lot of data to present to a user. Perhaps this is a set of preferences, options, or a profile. There is either too much information to present on a single page, or the information is logically separated into categories. For example, a user’s profile might contain their contact information, their login information, and settings. You want to present this information using one of the Flex navigation containers, such as Accordion.


The trouble comes when it is time to set the controls. Usually you have retrieved the user’s current settings from the server. When the user picks any of the Accordion headers, you want the information from the server to set the controls (radio buttons, text input fields, etc.).

There are three ways to approach this. First, the wrong way. When you set up an Accordion you may be under the assumption that each of the panels’ controls are available to set whenever you like. Here for instance, this code handles the result of retrieving the information from the server and attempts to set the controls in the Accordion:

function handleResult(result) {
firstName.text = result.firstName;
...
userName.text = result.userName;
...
color.text = result.color;
...
}
...
<mx:Accordion ...>
<mx:Form id="contact">
<mx:FormItem label="First Name:">
<mx:TextInput id="firstName" />
</mx:FormItem>
...
</mx:Form>
...
</mx:Accordion>

This won’t work. The problem is that by default, the Accordion creates all of its immediate children (the three Forms), but none of the Forms’ children except for the first form (contact) because that one is initially visible. The handleResult() code for setting the firstName field will work, but the other fields will not get set because they won’t exist until the user navigates to them.

<mx:Accordion creationPolicy="all">

One way to handle this is to set the creationPolicy for the Accordion to “all”. This will instruct the Flex framework to not only create the Accordion’s immediate children, but to create their children as well. Now the handleResult function will work because all of the components will exist. The problem with this is that it causes the application to take longer to start up as all of the controls need to be created. That’s why the default creationPolicy is to set “auto”.

<mx:Model id="prefs">
<firstName>{firstName.text}</firstName>
...
<userName>{userName.text}</userName>
...
<color>{color.text}</color>
...
</mx:Model>

The other way, and best way, to handle this, is to use a Model and leave the creationPolicy set to “auto”. This way, the controls are populated from the Model and the resultHandler can fill the model when the results come back:

function resultHandler(result) {
prefs.firstName = result.firstName;
...
prefs.userName = result.userName;
...
prefs.color = result.color;
...
}
...
<mx:Accordion ...>
<mx:Form id="contact">
<mx:FormItem label="First Name:">
<mx:TextInput id="firstName" text="{prefs.firstName}" />
</mx:FormItem>
...
</mx:Form>
...
</mx:Accordion>

Now when the user picks the “Settings” heading, the Accordion will create the controls and fill them from the Model. The creationPolicy of “auto” takes into account that a user might never pick a heading or a tab. Suppose for example, one of the panels of the Accordion has a DataGrid filled with a lot of data. Creating that can take time. If the user never decided to go there, you made them wait for no reason.

Using a Model also has the added benefit of being able to use Data Validation. For example, if the userName field is required and must be at least 8 letters long, you can specify this information and validate it against a <mx:StringValidator>:

<mx:FormItem label="User Name:" required="true'>
<mx:TextInput id="userName" text="{prefs.userName}" />
</mx:FormItem>
...
<mx:StringValidator field="prefs.userName" minLength="8" />

Summary

The moral of this story is that you should not try to manipulate the controls too much. Let Flex make your work easier. Use a Model to store the information being sent to or retrieved from the server. Let the navigation containers create their children as they need them, getting their values from a Model. Finally, if you are going to be sending data to the server, the Model makes it easier to use Flex’s data validation tags.