30 September 2008

Flex itemRenderers and Recycling Issues

Here's a funky behavior of itemRenderers inside any List-based component (for example, DataGrids). I ran into this and it drove me bunkers until I discovered what was causing it. Here's the scenario.

You have a DataGrid that contains an itemRenderer in one or more columns. Let's say you have a Button control in the renderer that browses for a file on your hard drive and plugs the filename into a TextInput within the same itemRenderer. All is fine -- until you scroll the DataGrid.

You'll notice that other, random TextInput controls in the same column have the same value. What the heck is going on? First inclination is to doubt your event handling code -- it's probably writing to more than one row. After much blood, sweat, and tears, and a lot of research, the answer reveals itself: The itemRenderers are recycled in the List-based controls. In other words, as you scroll, you'll notice the same value present in other itemRenderers without you having updated them. Also, if you scroll up to your updated row, the TextInput field is now blank!

Some articles that will help are here,
There are solutions to this recycling issue (described in the articles). I'm implementing one and will write more as I get it working.

25 September 2008

Strange Behavior in Flex Builder 3

I've noticed that at least in my copy of Flex Builder 3, the code-completion feature doesn't seem to work entirely correctly. I was trying to define a variable of type ListBaseContentHolder, but typing the dot "." after listClasses brought up a list of available classes -- but not ListBaseContentHolder!

var lb:mx.controls.listClasses.

All the online documentation said it was there, but Flex Builder wouldn't show it. I typed it in manually,

var lb:mx.controls.listClasses.ListBaseContentHolder;

and it compiled just fine. What's going on here?

Update, 9/30/2008: Apparently, by design, the folks at Adobe don't want you accessing some of the more arcane classes. Not sure why -- this is not arcane; I've been using it to get my work done :-)

Online XML-to-DTD Converter

For those who know their XML structure but need a little automated help with generating the DTD, there's a cool online tool. Very cool.

24 September 2008

Flex Validator Error Message Issue - Found Solution

Flex's validators are great but they're a little too subtle in notifying the user of errors: They mark the error field on the form with a red border. If you roll over the field, you'll see the error in a red tooltip. Why not have an option to display the validation error when it occurs, instead of having to mouse over to see it?

Well, here's a solution by Steven Gemmen. When you detect the error, dispatch an event to fool the field into thinking there's been a mouseover. Of all the solutions I've seen, this is the best/easiest.

The only problem I've run into is that the ValidationResultEvent's field property is null, even though the field has thrown the error. So I'm storing the source property in the subfield, generated from a custom validator,

  _results.push(new ValidationResult(true, super.source.toString().substring(super.source.toString().lastIndexOf(".")+1), "BadFileName", _errorMessage));  
return _results;

Not elegant, but it fixes the issue. Back on the page, I call the custom validator's Validate() method manually and receive the ValidateResultEvent.

  if (results.type == ValidationResultEvent.INVALID){
var val:ValidationResult = results.results;

This calls the function to activate the error tooltip,

  private function setValidationFocus(objName:String):void{
var frmObj:TextInput = this[objName];

frmObj.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));

Now to figure out why I'm not able to get the field property. Also, how do you remove the tooltip when the user clicks into the field?

22 September 2008

Adobe CS4 Launch Event

Hi, all. Adobe will launch their CS4 Suite on Tuesday, 9 a.m. Pacific Time. You can get details on the BrilliantEvent site.

Flex 4 - Download the Beta SDK

Flex 4, codenamed "Gumbo," is available for download from Adobe's OpenSource site. To get it installed and running in Flex Builder 3, you can use the tutorial at FlexExamples.

Exporting Data from SQL Server Express 2005

One area in which SQL Server Express is sorely lacking is its import/export capabilities. You can download the Microsoft SQL Server 2005 Express Edition Toolkit, but that still won't generate the INSERT statements to populate your tables on another server. If you navigate to following folder, you can run the DTS Wizard tool,

C:\Program Files\Microsoft SQL Server\90\DTS\Binn

After some Google searches, this result turned up from Vyas Kondreddi. With some tweaking, it can probably work for other databases, too.

Why Use Flex?

As Web developers, we have some options these days in the realm of RIA, AJAX being one. So why use Flex? To me, one answer is how Flex separates the presentation and data access layers.

This means that the Flex app is independent of the back-end: You can use any server technology that meets your requirements -- ColdFusion, J2EE, PHP, .NET... Because so much of Flex is designed around XML (even the MXML document), you can use something as basic as an HTTPService call to read and write data to your data store.

Thus, if in a few months your boss comes to you and says, "We're going with PHP," and you've been using .NET, you don't panic. The Flex front-end remains the same -- just change a little of the plumbing to connect to a PHP app instead. That's why the XML data format is so attractive: Any Web app can generate it.

What are some reasons you're using Flex? Feel free to post comments.

The Power of Flex's resultFormat E4X

While researching how to bind XML data to a Flex AdvancedDataGrid, I saw various examples that had the data converted to array objects. That might have been the only way to work with XML prior to ActionScript 3.0. Now however, a new set of classes and functionality, known as E4X (ECMAScript-for-XML), make life easier for developers.

Playing around, I discovered that, on the HTTPService object, a simple property allows the data to be accessible via simple XML calls,

service.resultFormat = "e4x";

This enables your datagrid's columns' dataField to simply have your XML element or attribute name as its value. For example, to read an id attribute off of the root element of your XML, you'd use dataField="@id".

Flex and XML - Don't Forget the ContentType

Hi, all. Hope everyone had a great weekend. I came across an interesting problem last week with Flex 3: A Java servlet produced perfectly fine XML via the SAX (Simple API for XML) package, but the SWF file kept having a hiccup when it tried to read the data,

private function useHttpService():void {
service = new HTTPService();
service.url = "http://myserver/myServlet";
service.method = "POST";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);

private function httpResult(event:ResultEvent):void {
premiums = XML(event.result);

// Read the XML directly (E4X) in the datagrid.
this.dgPremiums.dataProvider = premiums.premium;

// Fetch the rootCause and display in Alert.
private function httpFault(event:FaultEvent):void {
var errorMessage:ErrorMessage = event.message as ErrorMessage;
Alert.show("rootCause: " + errorMessage.rootCause.toString());

In the above code, I changed the FaultEvent handler to display an object as an ErrorMessage, as per Sujit's great article. Finally, it showed the error,

IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032: Stream Error. URL: myServlet"

Hmm. Flex errors can sometimes be tricky. A quick check on a Flex error lookup tool, and this page provided some answers, though not what I thought. One person had posted about having to remove the contentType from the HTTPService object. Mine was missing it. So I added it and voila! Flex fetched the data with no errors.

A little more digging and I realized that my Java servlet was emitting XML data, with the contentType set to "text/xml". Flex needed that hint of what data to expect. So adding this line to the useHTTPService() method fixed the headache,

service.contentType = "application/xml"; // Must have this or will get IOError -- servlet generates XML document.