by Adobe

adobe_logo_bio

Created

22 March 2010

Requirements
User level
All
A data model is an ActionScript object that contains properties that you use to store application-specific data. Data models provide a way to store data in the Flex application before it is sent to the server, or to store data sent from the server before using it in the application. Communication between an application built with Adobe Flex and the server is required only to retrieve data not yet available to the Flex application and to update a server-side data source with new data from the Flex application.
 
You do not need to connect to a server to use a model. For example, you can populate a static model in MXML or ActionScript or from a local XML file.
 
You can define a data model in an MXML tag, ActionScript function, or an ActionScript class. A model written in MXML is useful for rapid development and simple data storage, but it does not provide any additional functionality, and you cannot set the data types of the model's properties. Use an ActionScript-based class if you want to set data types and provide methods for additional functionality. In general, use MXML-based models for simple data structures and use ActionScript for more complex structures and client-side business logic. In the Model-View-Controller (MVC) design pattern, the data model represents the model tier.
 
Note: The Model-View-Controller (MVC) design pattern offers a generic solution to the common problem of tight coupling in applications by separating the business logic from the presentation logic and encapsulating any tight coupling in a single location. Data in an application forms the Model, the presentation layer is the View and the Controller mediates between the two and contains business logic. For a good introduction to MVC and other design patterns, see the Head First Design Patterns book by O'Reilly.
 
When you plan an application, you determine the kinds of data that the application must store and how that data must be manipulated. This helps you decide what types of data models you need. For example, suppose you decide that your application must store data about employees. A simple employee model might contain name, department, and e-mail address properties.
 
You can define data models in Flex in the following ways:
 

 
Using the <fx:Model> tag

The most common type of MXML-based model is the <fx:Model> tag, which is compiled into an ActionScript Object, or a tree of objects when your data is in a hierarchy, with no type information. The leaves of the Object tree are scalar values. Because models that are defined in <fx:Model> tags contain no type information or business logic, you should use them only for the simplest cases. Define models in ActionScript classes when you must have the typed properties or you want to add business logic.
 
You can either define the data for an <fx:Model> tag inline in the MXML file or use the source property of the tag to load in the data from an external data file. When using the source property, the external data file is compiled into the SWF file. It is not loaded in at run time.
 
The model declaration, in-line in the tag or in the source file, must have a single root node that contains all other nodes. You can use MXML binding expressions, such as {employeeEmail.text} in the model declaration. This way you can bind the contents of form fields to a structured data representation.
 
In the following example, you define a model to hold employee details. The model uses data binding to receive its data from various form controls in the user interface. The email data node, for example, gets its value from the text property of the employeeEmail TextInput control, whenever that value changes. Similarly, the name.first and name.last properties on the modelEmployee data model use data binding to get their values from the employeeName text field.
 
Tip: You can simplify the example by using two text fields, one for the employee's first name and one for the last name. If you build the example this way, you can bind the employee.name.first property to employeeFirstName.text property and the employee.name.last property to employeeLastName.text property. This simplifies the code because you don't have to process the string in a single employeeName text field to split it into a first name and a last name. However, you must decide which is more important: making your job easier or making it easier for your users to use your applications?
 
In this example, it is easier for a user to type their full name into a single text field. Splitting the employee's name into two text fields makes your job as a developer easier but complicates your user's task. Keep this in mind when developing our own applications. (In a real-world application, you would use more sophisticated logic to account for middle names and perform other validation on the name input.)
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- DataModelsModelTag.mxml --> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="360" height="240"> <fx:Declarations> <!-- This model holds information on a single employee --> <fx:Model id="modelEmployee"> <employee> <name> <first>{employeeName.text.substring(0, employeeName.text.indexOf(" "))}</first> <last>{employeeName.text.substring(employeeName.text.indexOf(" ")+1)}</last> </name> <department>{employeeDepartment.selectedItem}</department> <email>{employeeEmail.text}</email> </employee> </fx:Model> </fx:Declarations> <!-- Script to process the addition of a new employee --> <fx:Script> <![CDATA[ import mx.controls.Alert; private function addEmployee(event:MouseEvent):void { var message:String = "Name: "; message += modelEmployee.name.first + " " + modelEmployee.name.last + "\r"; message += "Department: " + modelEmployee.department + "\r"; message += "Email: " + modelEmployee.email; Alert.show(message, "New employee added!"); } ]]> </fx:Script> <!-- User Interface --> <s:Panel title="New employee details"> <mx:Form> <mx:FormItem label="Name:"> <s:TextInput id="employeeName"/> </mx:FormItem> <mx:FormItem label="Department:" width="100%"> <s:ComboBox id="employeeDepartment"> <s:dataProvider> <s:ArrayList> <fx:String>Administration</fx:String> <fx:String>CEO's Office</fx:String> <fx:String>Development</fx:String> <fx:String>Finance</fx:String> <fx:String>IT</fx:String> <fx:String>Support</fx:String> </s:ArrayList> </s:dataProvider> </s:ComboBox> </mx:FormItem> <mx:FormItem label="Email:"> <s:TextInput id="employeeEmail"/> </mx:FormItem> </mx:Form> <s:controlBarContent> <s:Button label="Add employee" click="addEmployee(event);"/> </s:controlBarContent> </s:Panel> </s:Application>
 
Result

 
Using script-based models

As an alternative to using an MXML-based model, you can define a model as a variable in an <fx:Script> tag. The following example is identical to the previous one but has the model defined in an ActionScript script block.
 
Tip: Define your model in MXML if you want to more easily take advantage of data binding using curly bracket syntax.
 
In the following example, you define your model in ActionScript as a hierarchy of objects. In the initialize event handler, you add the updateModel() method as the event handler for the change event on the various form items in your View. The updateModel() method acts like a View Helper. It inspects the controls in your view and updates the model with the data values that the user has input into them. You also define a method called validateModel() that performs very simple validation on the model and sets a flag called modelValid. You bind the Add employee button to the modelValid flag so that the user can only submit the form if the model is valid.
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- DataModelsModelAS.mxml --> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="360" height="240" initialize="initializeHandler(event);"> <fx:Script> <![CDATA[ import mx.events.FlexEvent; import mx.controls.Alert; // Boolean to keep track of valid the model is valid [Bindable] public var modelValid:Boolean = false; // Model private var modelEmployee:Object = { name: { first:"", last:"" }, department:"", email:"" } // Set up listeners for form item change events // when the application starts. private function initializeHandler(event:FlexEvent):void { employeeName.addEventListener(Event.CHANGE, updateModel); employeeDepartment.addEventListener(Event.CHANGE, updateModel); employeeEmail.addEventListener(Event.CHANGE, updateModel); } // Gets called when a form item on the view changes. // Acts like a View Helper: It inspects the view to // update the model with data supplied by the user. private function updateModel(event:Event):void { // Split the employee's full name string into // first name and last name strings. var employeeFullName:String = employeeName.text; var nameSpaceIndex:uint = employeeFullName.indexOf(" "); var employeeFirstName:String = employeeFullName.substring(0, nameSpaceIndex); var employeeLastName:String = employeeFullName.substring(nameSpaceIndex+1); // Store data values from the view in the model. modelEmployee.name.first = employeeFirstName; modelEmployee.name.last = employeeLastName; modelEmployee.department = employeeDepartment.selectedItem; modelEmployee.email = employeeEmail.text; // Do some simple validation on the model. validateModel(); } // A very simple custom validation method. private function validateModel():void { modelValid = modelEmployee.name.first != "" && modelEmployee.name.last != "" && modelEmployee.department != "" && modelEmployee.email != ""; } // The handler for the Add employee button private function addEmployee (event:MouseEvent):void { // Display the data values in the model var message:String = "Name: "; message += modelEmployee.name.first + " " + modelEmployee.name.last + "\r"; message += "Department: " + modelEmployee.department + "\r"; message += "Email: " + modelEmployee.email; Alert.show(message, "New employee added!"); } ]]> </fx:Script> <s:Panel title="New employee details"> <mx:Form> <mx:FormItem label="Name:"> <s:TextInput id="employeeName"/> </mx:FormItem> <mx:FormItem label="Department:" width="100%"> <s:ComboBox id="employeeDepartment"> <s:dataProvider> <s:ArrayList> <fx:String>Administration</fx:String> <fx:String>CEO's Office</fx:String> <fx:String>Development</fx:String> <fx:String>Finance</fx:String> <fx:String>IT</fx:String> <fx:String>Support</fx:String> </s:ArrayList> </s:dataProvider> </s:ComboBox> </mx:FormItem> <mx:FormItem label="Email:"> <s:TextInput id="employeeEmail"/> </mx:FormItem> </mx:Form> <s:controlBarContent> <s:Button label="Add employee" enabled="{modelValid}" click="addEmployee(event);"/> </s:controlBarContent> </s:Panel> </s:Application>
 
Result

 
Using class-based models

As with MXML-based models, you cannot type the properties of a script-based model. To type properties, you must use a class-based model.
 
Using an ActionScript class as a model is a good option when you have to store complex data structures with typed properties, or when you want to execute client-side business logic by using application data. Also, the type information in a class-based model is retained on the server when the model is passed to a server-side data service.
 
The following example shows the employee model defined in an ActionScript class called EmployeeModel. The EmployeeModel model class contains various typed properties as well as accessor methods (getter/setters), a simple custom validation method, and a method that returns a Transfer Object.
 
Note: A Transfer Object (also known as Value Object) is a simple object that contains just the data required to carry out a certain unit of business logic. In the following example, the Employee transfer object (EmployeeTO) contains only typed properties that describe an employee. It does not have methods like the model class. Transfer Objects are useful when moving data between the tiers by using technologies such as Flash Remoting and JSON that automatically serialize and deserialize complex objects across tiers while maintaining type information.
 
For more information on Transfer Objects, see how they are used in the Arp framework.
 
When using a class-based model, you can either instantiate it in ActionScript or in MXML. In the following example, you instantiate the model in MXML and set its id property to modelEmployee. Then, when defining the user interface, you bind various form controls to properties in this model and you use the change events broadcast by the form controls to update the data model.
 
 
Example
EmployeeModel.as
 
package { public class EmployeeModel { private var _firstName:String = ""; private var _lastName:String = ""; private var _department:uint = 0; private var _email:String = ""; [Bindable] public var modelValid:Boolean = false; [Bindable] public var departments:Array; public function EmployeeModel() { departments = [ "Administration", "CEO's Office", "Development", "Finance", "IT", "Support" ]; } public function set name(employeeFullName:String):void { // Split the employee's full name string into // first name and last name strings and store them separately. var nameSpaceIndex:uint = employeeFullName.indexOf(" "); _firstName = employeeFullName.substring(0, nameSpaceIndex); _lastName = employeeFullName.substring(nameSpaceIndex+1); // Do some simple validation on the model. validateModel(); } [Bindable] public function get department():uint { return _department; } public function set department(department:uint):void { _department = department; validateModel(); } public function set email(email:String):void { _email = email; validateModel(); } public function get name():String { return firstName + " " + lastName; } public function get firstName():String { return _firstName; } public function get lastName():String { return _lastName; } public function get departmentName():String { return departments[_department]; } public function get email():String { return _email; } // Returns a Transfer Object (also known as a Value Object). public function get transferObject():EmployeeTO { var employeeTO:EmployeeTO = new EmployeeTO(); employeeTO.firstName = firstName; employeeTO.lastName = lastName; employeeTO.department = department; employeeTO.email = email; return employeeTO; } // A very simple custom validation method. private function validateModel():void { modelValid = firstName != "" && lastName != "" && email != "" && email.indexOf("@") < email.indexOf("."); } } }
EmployeeTO.as
 
package { public class EmployeeTO { public var firstName:String; public var lastName:String; public var department:uint; public var email:String; } }
Main application MXML file
 
<?xml version="1.0" encoding="utf-8"?> <!-- DataModelsModelClass.mxml --> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="360" height="240" xmlns:local="*"> <fx:Script> <![CDATA[ import mx.controls.Alert; // The handler for the Add employee button private function addEmployee(event:MouseEvent):void { // Display the data values in the model var message:String = "Name: "; message += modelEmployee.lastName + ", " + modelEmployee.firstName + "\r"; message += "Department: " + modelEmployee.departmentName + "\r"; message += "Email: " + modelEmployee.email; Alert.show(message, "New employee added!"); } ]]> </fx:Script> <fx:Declarations> <local:EmployeeModel id="modelEmployee"/> </fx:Declarations> <s:Panel title="New employee details"> <mx:Form> <mx:FormItem label="Name:"> <s:TextInput id="employeeName" change="{modelEmployee.name = employeeName.text;}"/> </mx:FormItem> <mx:FormItem label="Department:" width="100%"> <mx:ComboBox id="employeeDepartment" dataProvider="{modelEmployee.departments}" selectedIndex="{modelEmployee.department}" change="{modelEmployee.department=employeeDepartment.selectedIndex;}"/> </mx:FormItem> <mx:FormItem label="Email:"> <s:TextInput id="employeeEmail" change="{modelEmployee.email=employeeEmail.text;}"/> </mx:FormItem> </mx:Form> <s:controlBarContent> <s:Button label="Add employee" enabled="{modelEmployee.modelValid}" click="addEmployee(event);"/> </s:controlBarContent> </s:Panel> </s:Application>

 
Using the <fx:XML> tag

In Flex, you can define your models as XML and take advantage of the improved XML processing capabilities in the new ECMAScript for XML (E4X) specification. E4X defines a new set of classes and functionality that make it easy to work with XML data.
 
You can create an XML-based model using the <fx:XML> tag or through ActionScript. In ActionScript 3, XML is a native datatype.
 
An <fx:XML> tag represents literal XML data. Setting the format property to e4x creates an XML object which implements E4X. For backward compatibility, when the format property is not explicitly set to e4x, the type of the object created is flash.xml.XMLNode.
 
In the following example, you create an XML-based data model using the <fx:XML> tag.
 
Note: Compare this example to the one on using the <fx:Model> tag and note the similarities between the two.
 
 
Example
<?xml version="1.0" encoding="utf-8"?> <!-- DataModelsXMLTag.mxml --> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="360" height="240"> <fx:Declarations> <!-- This model holds information on a single employee --> <fx:XML id="modelEmployee" format="e4x"> <employee> <name> <first>{employeeName.text.substring(0, employeeName.text.indexOf(" "))}</first> <last>{employeeName.text.substring(employeeName.text.indexOf(" ")+1)}</last> </name> <department>{employeeDepartment.selectedItem}</department> <email>{employeeEmail.text}</email> </employee> </fx:XML> </fx:Declarations> <!-- Script to process the addition of a new employee --> <fx:Script> <![CDATA[ import mx.controls.Alert; private function addEmployee (event:MouseEvent):void { var message:String = "Name: "; message += modelEmployee.name.first + " " + modelEmployee.name.last + "\r"; message += "Department: " + modelEmployee.department + "\r"; message += "Email: " + modelEmployee.email; Alert.show(message, "New employee added!"); } ]]> </fx:Script> <!-- User Interface --> <s:Panel title="New employee details"> <mx:Form> <mx:FormItem label="Name:"> <s:TextInput id="employeeName"/> </mx:FormItem> <mx:FormItem label="Department:" width="100%"> <s:ComboBox id="employeeDepartment"> <s:dataProvider> <s:ArrayList> <fx:String>Administration</fx:String> <fx:String>CEO's Office</fx:String> <fx:String>Development</fx:String> <fx:String>Finance</fx:String> <fx:String>IT</fx:String> <fx:String>Support</fx:String> </s:ArrayList> </s:dataProvider> </s:ComboBox> </mx:FormItem> <mx:FormItem label="Email:"> <s:TextInput id="employeeEmail"/> </mx:FormItem> </mx:Form> <s:controlBarContent> <s:Button label="Add employee" click="addEmployee(event);"/> </s:controlBarContent> </s:Panel> </s:Application>

 
For more information