Archive

Posts Tagged ‘flex’

Converting XML data to strongly typed AS3 Object

February 18, 2009 Leave a comment

Context / Problem :

The Use of the HttpService gives us the opportunity to retreive XML data from a server.
But … the problem starts when we receive these data : how could we manipulate these data from a strongly typed manner ?
Let’s take an example to illustrate the issue :

The following code retrieves xml data and registers a callback to parse the result :

var httpService:HTTPService = new HTTPService();
httpService.addEventListener(ResultEvent.RESULT, onLoadListResult);
httpService.url="TodoItems.xml";
httpService.resultFormat=HTTPService.RESULT_FORMAT_OBJECT;
httpService.send();

private function onLoadListResult(e:ResultEvent):void {
	var resultList:ArrayCollection = new ArrayCollection();
	for each (var o:ObjectProxy in  ArrayCollection(e.result.List.TodoItemVO)) {
		trace(o.title);
	}
}

The content of TodoItems.xml is the following :

<?xml version="1.0" encoding="utf-8"?>
<List>
	<TodoItemVO>
		<id>1</id>
		<title>Simple title</title>
		<detail>detail</detail>
	</TodoItemVO>
	<TodoItemVO>
		<id>2</id>
		<title>another Title</title>
		<detail>detail2</detail>
	</TodoItemVO>
</List>

So the output for this will be the following :

Simple title
another Title

It works … so where is the issue ?
Well what I would like is to cast the result in strongly type object.
The direct solution would be to create my typed object and copy each attribut in it.
My callback function would be something like this :

private function onLoadListResult(e:ResultEvent):void {
	var resultList:ArrayCollection = new ArrayCollection();
	for each (var o:ObjectProxy in  ArrayCollection(e.result.List.TodoItemVO)) {
		var todoItemVO:TodoItemVO = new TodoItemVO();
		todoItemVO.id = o.valueOf().id;
		todoItemVO.title = o.valueOf().title;
		todoItemVO.detail = o.valueOf().detail;
		resultList.addItem(todoItemVO);
	}
}

But what if I have more than 3 attributes to copy ?

Solution :

I’ve found this solution from the Darron Schall blog’s in this blog entry :

He has developped an utility object (ObjectTranslator) that will copy your data in the strongly typed object with only one line of code :

ObjectTranslator : converts a plain vanilla object to be an instance of the class passed as the second variable.  This is not a recursive funtion and will only work for the first level of nesting.  When you have deeply nested objects, you first need to convert the nested objects to class instances, and then convert the top level object.

My code will then look like this :

private function onLoadListResult(e:ResultEvent):void {
	var resultList:ArrayCollection = new ArrayCollection();
	for each (var o:ObjectProxy in  ArrayCollection(e.result.List.TodoItemVO)) {           
		resultList.addItem(ObjectTranslator.objectToInstance(o.valueOf(), TodoItemVO) as TodoItemVO);
	}
}

Advertisements
Categories: Actionscript Tags: ,

Two way binding with Flex

January 28, 2009 1 comment

Having a good api for binding ui components to the data model has became a must have feature. Since I’m playing with Flex lately I’ve quickly test how to use its binding feature.

Let say you have a VO object like this one :


package org.test.vo {

    [Bindable]
    public class PersonVO  {

        public var age:int;
        public var firstName:String;
        public var lastName:String;
    }
}

Notice the [Bindable] annotation added before the class definition, this is telling the compiler that all the public attribut inside the class should be able to dispatch an event when their value are changed so that they can be used as the source of data binding.

Solution 1 :

The following Flex code can be used to display the PersonVO data :


    <mx:Form>
        <mx:FormItem label="First Name">
            <mx:TextInput id="firstNameId"/>
        </mx:FormItem>       
        <mx:FormItem label="Last Name">
            <mx:TextInput id="lastNameId"/>
        </mx:FormItem>
        <mx:FormItem label="Age">
            <mx:TextInput id="ageId"/>
        </mx:FormItem>
    </mx:Form>

If you want a “two way” binding between the UI and the model you need to write the following


    <mx:Binding source="personVO.firstName" destination="firstNameId.text" />
    <mx:Binding source="firstNameId.text" destination="personVO.firstName" />

    <mx:Binding source="personVO.lastName" destination="lastNameId.text" />
    <mx:Binding source="lastNameId.text" destination="personVO.lastName" />

    <mx:Binding source="personVO.age.toString()" destination="ageId.text" />
    <mx:Binding source="int(ageId.text)" destination="personVO.age" />

Note : since age is an int type we need to write some extra code to tell flex how to cast from String to int and vice versa.

Solution 2 :

The binding can also be described the following way :


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:local="*">

    <mx:Script>
        <!&#91;CDATA&#91;
            import mx.controls.Alert;
            private function showPersonValue():void {
                Alert.show(    "firstName = " + aPerson.firstName + "\n" +
                             "lastName = " + aPerson.lastName + "\n"+
                             "age = " + aPerson.age , "Info");
            }
        &#93;&#93;>
    </mx:Script>

    <local:PersonVO id="aPerson">
        <local:firstName>{firstNameId.text}</local:firstName>
        <local:lastName>{lastNameId.text}</local:lastName>
        <local:age>{int(ageId.text)}</local:age>
    </local:PersonVO>

    <mx:Form>
        <mx:FormItem label="First Name">
            <mx:TextInput id="firstNameId" text="{aPerson.firstName}"/>
        </mx:FormItem>
        <mx:FormItem label="Last Name">
            <mx:TextInput id="lastNameId" text="{aPerson.lastName}"/>
        </mx:FormItem>
        <mx:FormItem label="Age">
            <mx:TextInput id="ageId" text="{aPerson.age}"/>
        </mx:FormItem>
    </mx:Form>

    <mx:Button label="Show Person Value" click="showPersonValue()"/>

</mx:Application>

twowaysmappingsolution2

Another solution for creating a two way binding using a “in-house utility api” found here

This solution gives the following to describe the two way binding :

...
<mx:Script>
	<!&#91;CDATA&#91;
		public var userModel : UserModel;
	&#93;&#93;>
</mx:Script>
<mx:Form>
	<mx:FormItem label="First Name">
		<mx:TextInput id="txtFirstName"/>
	</mx:FormItem>
</mx:Form>
<ModelBinding model="{userModel}" field="firstName" target="{txtFirstName}"/>
...

In my opinion the main drawback for this solution is that we are losing the error warning during compilation time : if you change field name from “firstname” to “fname” for example you won’t be informed of this error.
Finally
I would like to point out this feature request posted at adobe asking for indicating two way binding in mx:binding tag and the following solution :  Two-way Data Binding – Functional and Design Specification.

Categories: Uncategorized Tags: