Tuesday, October 21, 2008

Today I'm a developer

For the last few weeks I have been a Flex developer, and I've learned about something really helpful.

Flex value objects.

Well these little AS classes have saved me some heartache and headaches. I was dumping everything into an xmlListCollection and then creating ArrayCollections of display objects with the data from the xmlListCollection. It started to get messy. No more! Value objects are way easier to manage.

Here’s an example of how to create one in case you’ve never done it before. (ps this is using the Cairngorm framework).

Okay first things first. What are you going to pull from your xml? In my example I am pulling a "Section" and each Section has a "SubSection". In this case I'd need two value objects. One for my Section and one for my SubSection. Stick them in a folder called vo.

Here is my SectionVO.as:


package com.vo
{
import com.adobe.cairngorm.vo.ValueObject;
import mx.collections.ArrayCollection;

[Bindable]
public class SectionVO implements ValueObject
{
public var title:String = "NA";
public var subsections:ArrayCollection = new ArrayCollection();

}
}


Each Section has a title and a bunch of subsections. So I have a String and an ArrayCollection.

Here is my SubSectionVO.as:

package com.vo
{
import com.adobe.cairngorm.vo.ValueObject;

[Bindable]
public class SubSectionVO implements ValueObject
{
public var title:String = "NA";
public var header:String = "NA";
public var body:String = "NA";

}
}


Each SubSection has a title, a header, and a body. So I have 3 public String vars.

Inside your main Application mxml file call the HTTP service and use the data to populate the value objects.

Here is the result handler. It gets your XML and puts it inside an XMLList. Then it calls the method that populates the value objects. Once that’s done it adds the initial “View” object (i.e. everything you see on the screen when the Application loads).


// Result handler - gets called after RSS is loaded.
private function contentResultHandler(event:ResultEvent):void
{
// Get sections from XML
var xmlList:XMLList = XML(event.result).sections.section;
fillSections( xmlList );

// Add child to show view now that all content is loaded
var view:View = new View();
view.id="view";
this.addChild(view)
}


This method populates the value objects and then adds each Section to an ArrayCollection inside the ModelLocator that will be used throughout the rest of the application.


// Populate Section VOs with data and add to ML.allsectionsac
public function fillSections( xmlList:XMLList ):void
{
// For each section in the data
for each ( var sectionData:XML in xmlList )
{

// Populate the Section data
var sectionVO:SectionVO = new SectionVO();
sectionVO.title = sectionData.title;

// For each sub-section in the section
for each ( var subSectionData:XML in sectionData.subsections.subsection )
{
// Populate the SubSection
var subsectionVO:SubSectionVO = new SubSectionVO();
subsectionVO.title = subSectionData.title;
subsectionVO.header = subSectionData.header;
subsectionVO.body = subSectionData.body;

// Add SubSectionVO to the SectionVO
sectionVO.subsections.addItem(subsectionVO);
}

// Add section VOs to ModelLocator array collection
ML.allSectionsac.addItem(sectionVO);
}
}


And of course, you're going to need your fault handler in case the Application can't find your xml data in the first place.


// Fault handler - displays the error.
private function contentFaultHandler(event:FaultEvent):void
{
Alert.show(event.fault.message, "Could not load content feed");
}


Inside your MXML create the HTTPService object.


<HTTPService
id="contentService"
url="assets/xml/content.xml"
resultformat="e4x"
result="contentResultHandler(event)"
fault="contentFaultHandler(event)">
</mx:httpservice>


And that’s it! Now all your data from the xml is easily accessible inside your application.

Now all you do is use your ArrayCollection inside your ModelLocator. You will probably have to create a Display Object component as well. Your Display Object would have one Bindable public var of type your value object (i.e. [Bindable] public var sectionObj:SectionVO; ). In my example below I also refer to a SubSection object, which just be something simlar to this section object but with text objects getting their data from the SubSectionVO.

The Section Display Object component may look something like this:

Section.mxml

<mx:VBox
mx="http://www.adobe.com/2006/mxml"
com="com.*">

<mx:script>
<![CDATA[
import com.vo.SubSectionVO;
import com.vo.SectionVO;

import model.ModelLocator;
[Bindable] private var ML:ModelLocator = ModelLocator.getInstance();

[Bindable] public var sectionObj:SectionVO;

public function init():void
{
getSubSections();
}

// Get all sub-sections and add them to section
public function getSubSections():void
{
for ( var n:int=0; n < sectionObj.subsections.length; n++ )
{
var subSectionView:SubSection = new SubSection();
subSectionView.subSectionObj = SubSectionVO(sectionObj.subsections.getItemAt(n));
this.addChild(subSectionView);
}
}
]]>
</mx:Script>

<mx:Label text="{sectionObj.title}" />

</mx:VBox>


Hope that was SOMEWHAT clear. Hope that helps someone out someday. I am sure I’ll be looking back on this post when I forget how to do this!