You use the data model feature to store data in an application before it is sent to the server, or to store data sent from the server before using it in the application.
A data model is an ActionScript object that contains properties that you use to store application-specific data. Communication between a Flex application 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 can use a data model for data validation, and it can contain client-side business logic. You can define a data model in MXML or ActionScript. In the model-view-controller (MVC) design pattern, the data model represents the model tier.
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 a data model in an MXML tag, an ActionScript function, or an ActionScript class. In general, you should use MXML-based models for simple data structures, and use ActionScript for more complex structures and client-side business logic.
You can place an <fx:Model> tag or an <fx:XML> tag in a Flex application file or in an MXML component file. The tag should have an id value, and it cannot be the root tag of an MXML component.
Declare an <fx:Model> tag or an <fx:XML> tag in an <fx:Declarations> tag. You define these tags in an <fx:Declarations> tag because they are not visual components.
The most common type of MXML-based model is the <fx:Model> tag, which is compiled into an ActionScript object of type mx.utils.ObjectProxy, which contains 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 need the typed properties or you want to add business logic.
The following example shows an employee model declared in an <fx:Model> tag:
<?xml version="1.0"?>
<!-- Models\ModelsModelTag.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<fx:Model id="employeemodel">
<employee>
<name>
<first/>
<last/>
</name>
<department/>
<email/>
</employee>
</fx:Model>
</fx:Declarations>
</s:Application>
An <fx:Model> child tag with no value is considered null. If you want an empty string instead, you can use a binding expression as the value of the tag, as the following example shows:
<?xml version="1.0"?>
<!-- Models\ModelTagEmptyString.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<fx:Model id="employeemodel">
<employee>
<name>
<!--Fill the first property with empty string.-->
<first>{""}</first>
<!--Fill the last property with empty string.-->
<last>{""}</last>
</name>
<!--department is null-->
<department/>
<!--email is null-->
<email/>
</employee>
</fx:Model>
</fx:Declarations>
</s:Application>
An <fx:XML> tag represents literal XML data. Setting the format property to e4x creates an XML object, which implements the powerful XML-handling standards defined in the ECMAScript for XML specification (ECMA-357 edition 2) (known as E4X). For backward compatibility, when the format property is not explicitly set to e4x, the type of the object created is flash.xml.XMLNode.
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 shows a very simple model defined in an ActionScript script block. It would be easier to declare this model in an <fx:Model> tag.
<?xml version="1.0"?>
<!-- Models\ScriptModel.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
[Bindable]
public var myEmployee:Object={
name:{
first:null,
last:null
},
department:null,
email:null
};
]]>
</fx:Script>
</s:Application>
There is no advantage to using a script-based model instead of an MXML-based model. 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 want 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 a model defined in an ActionScript class. This model is used to store shopping cart items in an e-commerce application. It also provides business logic in the form of methods for adding and removing items, getting an item count, and getting the total price.
package
{
[Bindable]
public class ShoppingCart {
public var items:Array = [];
public var total:Number = 0;
public var shippingCost:Number = 0;
public function ShoppingCart() {
}
public function addItem(item:Object, qty:int = 1,
index:int = 0):void {
items.splice(index, 0, { id: item.id,
name: item.name,
description: item.description,
image: item.image,
price: item.price,
qty: qty });
total += parseFloat(item.price) * qty;
}
public function removeItemAt(index:Number):void {
total -= parseFloat(items[index].price) * items[index].qty;
items.splice(index, 1);
if (getItemCount() == 0)
shippingCost = 0;
}
public function getItemCount():int {
return items.length;
}
public function getTotal():Number {
return total;
}
}
}
You declare a class-based model as an ActionScript component tag in an MXML file, as the following example shows:
<local:ShoppingCart id="cart" xmlns:local="*"/>
This component is in the same directory as the MXML file, as indicated by the XML namespace value *. For more information about specifying the location of components, see Using XML namespaces.
You can specify an external source for an <fx:Model> or <fx:XML> tag in a source property. Separating the content of a model from the MXML that defines the user interface improves the maintainability and reusability of an application.
The external source file can contain static data and data binding expressions, just like a model defined in the body of the <fx:Model> or <fx:XML> tag. The file referenced in a source property resides on the server and not on the client machine. The compiler reads the source value and compiles the source into the application; the source value is not read at run time. To retrieve XML data at run time, you can use the <mx:HTTPService> tag.
Using <fx:Model> and <fx:XML> tags with external sources is an easy way to reuse data model structures and data binding expressions. You can also use them to prepopulate user interface controls with static data by binding data from the model elements into the user interface controls.
The source property accepts the names of files relative to the current web application directory, as well as URLs with HTTP:// prefixes. In the following example, the content of the myEmployee1 data model is an XML file named content.xml in the local web application directory. The content of the myEmployee2 data model is a fictional HTTP URL that returns XML.
<fx:Model source="employees.xml" id="employee1"/> <fx:Model source="http://www.somesitel.com/employees.xml" id="employee2"/>
The source file must be a valid XML document with a single root node. The following example shows an XML file that could be used as the source of the <fx:Model source="employees.xml" id="Model1"/> tag.
<?xml version="1.0"?> <employees> <employee> <name>John Doe</name> <phone>555-777-66555</phone> <email>jdoe@fictitious.com</email> <active>true</active> </employee> <employee> <name>Jane Doe</name> <phone>555-777-66555</phone> <email>jndoe@fictitious.com</email> <active>true</active> </employee> </employees>
To validate the data stored in a data model, you use validators. In the following example, the <mx:EmailValidator>, <mx:PhoneNumberValidator>, <mx:ZipCodeValidator>, and <mx:SocialSecurityValidator> tags declare validators that validate the e-mail, phone, zip, and ssn fields of the registration data model. The validators generate error messages when a user enters incorrect data in TextInput controls that are bound to the data model fields.
<?xml version="1.0"?>
<!-- Models\ModelWithValidator.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<fx:Model id="reg">
<registration>
<name>{username.text}</name>
<email>{email.text}</email>
<phone>{phone.text}</phone>
<zip>{zip.text}</zip>
<ssn>{ssn.text}</ssn>
</registration>
</fx:Model>
<mx:Validator required="true"
source="{reg}" property="name"
trigger="{submit}"
triggerEvent="click"
listener="{username}"/>
<mx:EmailValidator source="{reg}" property="email"
trigger="{submit}"
triggerEvent="click"
listener="{email}"/>
<mx:PhoneNumberValidator source="{reg}" property="phone"
trigger="{submit}"
triggerEvent="click"
listener="{phone}"/>
<mx:ZipCodeValidator source="{reg}" property="zip"
trigger="{submit}"
triggerEvent="click"
listener="{zip}"/>
<mx:SocialSecurityValidator source="{reg}" property="ssn"
trigger="{submit}"
triggerEvent="click"
listener="{ssn}"/>
</fx:Declarations>
<!-- Form contains user input controls. -->
<s:Form>
<s:FormItem label="Name" required="true">
<s:TextInput id="username" width="200"/>
</s:FormItem>
<s:FormItem label="Email" required="true">
<s:TextInput id="email" width="200"/>
</s:FormItem>
<s:FormItem label="Phone" required="true">
<s:TextInput id="phone" width="200"/>
</s:FormItem>
<s:FormItem label="Zip" required="true">
<s:TextInput id="zip" width="60"/>
</s:FormItem>
<s:FormItem label="Social Security" required="true">
<s:TextInput id="ssn" width="200"/>
</s:FormItem>
<s:FormItem>
<!-- User clicks Button to trigger validation. -->
<s:Button id="submit" label="Validate"/>
</s:FormItem>
</s:Form>
</s:Application>
This example cleanly separates the user interface and application-specific data. You could easily extend it to create a three-tier architecture by binding data from the registration data model into an RPC service request. You could also bind user input data directly into an RPC service request, which itself is a data model.
For more information about validators, see Validating Data.
You can use a data model as a value object, which acts as a central repository for a set of data returned from method calls on one or more objects. This makes it easier to manage and work with data in an application.
In the following example, the tentModel data model stores the results of a web service operation. The TentDetail component is a custom MXML component that gets its data from the tentModel data model and displays details for the currently selected tent.
...
<!-- Data model stores data from selected tent. -->
<fx:Model id="tentModel">
<tent>
<name>{selectedTent.name}</name>
<sku>{selectedTent.sku}</sku>
<capacity>{selectedTent.capacity}</capacity>
<season>{selectedTent.seasonStr}</season>
<type>{selectedTent.typeStr}</type>
<floorarea>{selectedTent.floorArea}</floorarea>
<waterproof>{getWaterProof(selectedTent.waterProof)}</waterproof>
<weight>{getWeight(selectedTent)}</weight>
<price>{selectedTent.price}</price>
</tent>
</fx:Model>
...
<TentDetail id="detail" tent="{tentModel}"/>
...
The following example shows the MXML source code for the TentDetail component. References to the tent property, which contains the tentModel data model, and the corresponding tentModel properties are highlighted in boldface.
<?xml version="1.0" encoding="utf-8"?>
<!-- Models\myComponents\TentDetail.mxml-->
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
title="Tent Details">
<fx:Script>
<![CDATA[
[Bindable]
public var tent:Object;
]]>
</fx:Script>
<fx:Style>
.title{fontFamily:Arial;fontWeight:bold;color:#3D3D3D;fontSize:16pt;}
.flabelColor
{fontFamily:Arial;fontWeight:bold;color:#3D3D3D;fontSize:11pt}
.productSpec{fontFamily:Arial;color:#5B5B5B;fontSize:10pt}
</fx:Style>
<s:VGroup paddingLeft="10" paddingTop="10" paddingRight="10">
<s:Form verticalGap="0" paddingLeft="10" paddingTop="10"
paddingRight="10" paddingBottom="0">
<s:VGroup width="209" height="213">
<s:Image width="207" height="211"
source="./images/{tent.sku}_detail.jpg"/>
</s:VGroup>
<s:FormHeading label="{tent.name}" paddingTop="1"
styleName="title"/>
<mx:HRule width="209"/>
<s:FormItem label="Capacity" styleName="flabelColor">
<s:Label text="{tent.capacity} person"
styleName="productSpec"/>
</s:FormItem>
<s:FormItem label="Season"
styleName="flabelColor">
<s:Label text="{tent.season}"
styleName="productSpec"/>
</s:FormItem>
<s:FormItem label="Type" styleName="flabelColor">
<s:Label text="{tent.type}"
styleName="productSpec"/>
</s:FormItem>
<s:FormItem label="Floor Area" styleName="flabelColor">
<s:Label text="{tent.floorarea}
square feet" styleName="productSpec"/>
</s:FormItem>
<s:FormItem label="Weather" styleName="flabelColor">
<s:Label text="{tent.waterproof}"
styleName="productSpec"/>
</s:FormItem>
<s:FormItem label="Weight" styleName="flabelColor">
<s:Label text="{tent.weight}"
styleName="productSpec"/>
</s:FormItem>
</s:Form>
</s:VGroup>
</s:Panel>
Flex compiles the <fx:XML> tag into literal XML data in an ActionScript xml.XMLNode or XML object. This is different from the <fx:Model> tag, which Flex compiles into an Action object that contains a tree of ActionScript objects. To bind data into an <fx:XML> data model, you can use the curly braces syntax the same way you do with other data models. However, you cannot use a node within the data model as a binding source.
It's not a best practice to use the <mx:Binding> tag for this type of binding because doing so requires you to write an appropriate ActionScript XML command as the destination property of the <mx:Binding> tag. For more information about the <fx:XML> tag, see Defining a data model.
The following example shows an <fx:XML> data model with binding destinations in curly braces:
<?xml version="1.0"?>
<!-- Models\XMLBinding.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Declarations>
<fx:XML id="myEmployee" format="e4x">
<employee>
<name>
<first>{firstName.text}</first>
<last>{lastName.text}</last>
</name>
<department>{department.text}</department>
<email>{email.text}</email>
</employee>
</fx:XML>
</fx:Declarations>
<s:TextInput id="firstName"/>
<s:TextInput id="lastName"/>
<s:TextInput id="department"/>
<s:TextInput id="email"/>
</s:Application>
Navigation
Adobe and Adobe Flash Platform are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.