Archive for July 20th, 2009

20
Jul

Under the hood Flex data model using the fx:Model and fx:XML tags

When creating data model there are two popular ways to create data model in addition to VO / DTO. You can use the fx:Model and the fx:XML tags. These tags are mxmlc compiler tag. What it means is that the compiler handles these tags differently than the regular tags in MXML. In case you are like me and like to dig deep into how the mxmlc works than keep reading… In the Model or XML tags the source property can be set to an external source, however the compiler retrieve the information and set it as an ObjectProxy, which allow the object to be bindable, additionally it does direct assignment so there is no service call to retrieve the data as you may expect from an MXML tag. Consider the code below:


<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/halo"
			   minWidth="1024" minHeight="768"
                           creationComplete="creationCompleteHandler(event)">
	<fx:Script>
		<![CDATA[
			import mx.events.FlexEvent;

			protected function creationCompleteHandler(event:FlexEvent):void
			{
				trace("infoVO full name property: "+this.infoVO.fullName);
				trace("info2VO full name property: "+this.info2VO.fullName);
			}

		]]>
	</fx:Script>

	<fx:Declarations>

		<fx:Model id="infoVO">
			<root>
				<fullName>John Doe</fullName>
				<email>john@gmail.com</email>
				<phone>212-222-2222</phone>
				<zip>10001</zip>
			</root>
		</fx:Model>

		<fx:Model id="info2VO" source="Info.xml" />

	</fx:Declarations>

</s:Application>

We have two Model tags in the code and although one tag calls an xml using the source property and another one does direct assignment the mxmlc compile will generate the same code for both of these tags.

Take a look at what the compiler does when you use set infoVO and info2VO with the source property:


private function _DataModel_ObjectProxy2_i() : mx.utils.ObjectProxy
{
	var temp : mx.utils.ObjectProxy = new mx.utils.ObjectProxy();
	temp.fullName = "John Doe";
	temp.email = "john@gmail.com";
	temp.phone = "212-222-2222";
	temp.zip = 10001;
	info2VO = temp;
	return temp;
}

private function _DataModel_ObjectProxy1_i() : mx.utils.ObjectProxy
{
	var temp : mx.utils.ObjectProxy = new mx.utils.ObjectProxy();
	temp.fullName = "John Doe";
	temp.email = "john@gmail.com";
	temp.phone = "212-222-2222";
	temp.zip = 10001;
	infoVO = temp;
	return temp;
}

And here’s what the mxmlc code generated to create the binding tag:


    [Bindable(event="propertyChange")]
    public function get info2VO():mx.utils.ObjectProxy
    {
        return this._1945369341info2VO;
    }

    public function set info2VO(value:mx.utils.ObjectProxy):void
    {
    	var oldValue:Object = this._1945369341info2VO;
        if (oldValue !== value)
        {
            this._1945369341info2VO = value;
            this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "info2VO", oldValue, value));
        }
    }

	/**
	 * generated bindable wrapper for property infoVO (public)
	 * - generated setter
	 * - generated getter
	 * - original public var 'infoVO' moved to '_1184171033infoVO'
	 */

    [Bindable(event="propertyChange")]
    public function get infoVO():mx.utils.ObjectProxy
    {
        return this._1184171033infoVO;
    }

    public function set infoVO(value:mx.utils.ObjectProxy):void
    {
    	var oldValue:Object = this._1184171033infoVO;
        if (oldValue !== value)
        {
            this._1184171033infoVO = value;
            this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, "infoVO", oldValue, value));
        }
    }

Since the mxmlc compiler create an ObjectProxy component it allows us to bind these properties as in the example below:


<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/halo"
			   minWidth="1024" minHeight="768">

	<s:layout>
		<s:BasicLayout/>
	</s:layout>

	<fx:Declarations>
		<fx:Model id="infoVO">
			<root>
				<fullName>{fullNameTextInput.text}</fullName>
				<email>{emailTextInput.text}</email>
				<phone>{phoneTextInput.text}</phone>
				<zip>{zipTextInput.text}</zip>
			</root>
		</fx:Model>
	</fx:Declarations>	

	<mx:DataGrid x="11" y="164" id="dataGrid"
				 dataProvider="{infoVO}">
		<mx:columns>
			<mx:DataGridColumn
				headerText="fullName"
				dataField="fullName"/>
			<mx:DataGridColumn
				headerText="email"
				dataField="email"/>
			<mx:DataGridColumn
				headerText="phone"
				dataField="phone"/>
			<mx:DataGridColumn
				headerText="zip"
				dataField="zip"/>
		</mx:columns>
	</mx:DataGrid>

	<mx:Form>
		<mx:FormItem label="FullName">
			<s:TextInput
				id="fullNameTextInput"/>
		</mx:FormItem>
		<mx:FormItem label="Email">
			<s:TextInput
				id="emailTextInput"/>
		</mx:FormItem>
		<mx:FormItem label="Phone">
			<s:TextInput
				id="phoneTextInput"/>
		</mx:FormItem>
		<mx:FormItem label="Zip">
			<s:TextInput
				id="zipTextInput"/>
		</mx:FormItem>
	</mx:Form>
</s:Application>

Here’s a screen shot of the application:
Flex Data Model

It valuable to understand how the mxmlc works and use these tags when needed.