Sunday, November 11, 2007

Flex dynamically create ComboBox with dataProvider from HTTPService

Well, now I am working on my own (sponsored) project during my free time. Cut the long story short, I have been working on Stock Control application for a major eBay seller in Australia. The project has been running for about 4 years now. The application is complex and fun, it supports multiple sites and items synchronization.

The existing application runs on PHP5 and MySQL. Furthermore, NUSOAP is also used to support third-party Web Service API calls to the application.

Fun has the limit for this project until I recently come out with the idea to re-design the client user interface (UI) and the integration layer to connect to the existing business/backend layer. I have decided to taste the sweetness of Flex and Zend Framework and they are awesome!

Flex uses HTTPService to asynchronously get the data from the PHP that produces XML. This XML is used to bind to a datasource for a Flex component (e.g. ComboBox). If you are using MXML tag to create the ComboBox, and assign the dataProvider to HTTPService result, you won't have issue.

However, if you need to create the ComboBox dynamically using Action Script, when you try to bind the dataSource to the XML result from the HTTPService, you will get an error saying:

Cannot access a property or method of a null object reference

This is because the execution of binding the dataSource to the XML returned from HTTPService is faster than the HTTPService itself, for example:

You have HTTPService and ComboBox objects:

1 var httpTemp:HTTPService = new HTTPService();
2 httpTemp.url = http://www.tempuri.org/xml.php;
3 httpTemp.resultFormat = "e4x";
4 httpTemp.send();
5
6 var newComboBox:ComboBox = new ComboBox();
7 newComboBox.dataProvider = httpTemp.result;

Even though line 4 is executed first, however because it takes a while to return the XML data, thus when line 7 is executed, the httpTemp.result object does not exist yet and error occurs.

To solve this:
Create a bindable vars

[Bindable] public var xmlResult:XML;
[Bindable] public var newComboBox:ComboBox;

Create a result event handler for HTTPService:

private function httpTempResultHandler( e:ResultEvent ):void
{
xmlResult = e.result as XML;
newComboBox.dataProvider = xmlResult.Category;

}

Create the ComboBox object:

//create a new instance of ComboBox
newComboBox = new ComboBox();
var httpTemp:HTTPService = new HTTPService();

Create a dummy result:

var tempString:String = '0';
xmlResult = new XML(tempString);

Create a result event listener:

httpTemp.url = "http://www.tempuri.org/xml.php";
httpTemp.resultFormat = "e4x";
//add the result event listener
httpTemp.addEventListener(ResultEvent.RESULT, httpTempResultHandler, false, 0);
httpTemp.send();

Assign the XML to the dataProvider:

newComboBox.dataProvider = xmlResult.Category;

This assigns a dummy result to the dataProvider and when the HTTPService result event handler called, the bind-able xmlResult will be used with the result from the HTTPService.

No comments: