Jon asked me an interesting Flex based question. Now before I show any code, I'll remind folks - I'm still very much the Flex Padawan. Whatever I show here I expect could be done much better (in fact, be sure to read the final code sample as it was created by a true Flex Jedi). That being said, I'm proud to have at least had an idea of the ballpark of the solution! Ok, enough jibber jabber - let's get to the question. Jon was using Flash Remoting to talk to a ColdFusion component. His code made use of RemoteObject and method, a bit like so:

<mx:RemoteObject destination="ColdFusion" source="flextest" id="doubleService"> <mx:method name="double" result="handleResult(event)" fault="handleFault(event)" /> </mx:RemoteObject>

In this code block I've created a connection to a CFC, "flextest", and given the remote object an id of doubleService. I've defined a method called double (can you guess what it does?) and a result handler. Now I can take a field and set it up so that when you enter a value, it runs this method and sets the result. Something like so:

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">

<mx:RemoteObject destination="ColdFusion" source="flextest" id="doubleService"> <mx:method name="double" result="handleResult(event)" fault="handleFault(event)" /> </mx:RemoteObject>

<mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent;

public function handleFault(evt:FaultEvent):void { mx.controls.Alert.show(evt.toString()) }

public function handleResult(evt:ResultEvent):void { resultone.text = evt.result.toString() }

]]> </mx:Script>

<mx:VBox>

<mx:HBox> <mx:Text text="Field One" /> <mx:TextInput id="fieldone" change="doubleService.double(fieldone.text)" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultone" /> </mx:HBox>

</mx:VBox> </mx:Application>

I've got a simple set of fields here - one being the input - one for the output. When you enter a value, I fire off a request to the CFC to get the value. My result handler simply takes the result and puts it in the field. Simple, right? Well what happens when you add 2 more fields?

<mx:HBox> <mx:Text text="Field One" /> <mx:TextInput id="fieldone" change="doubleService.double(fieldone.text)" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultone" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Two" /> <mx:TextInput id="fieldtwo" change="doubleService.double(fieldtwo.text)" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resulttwo" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Three" /> <mx:TextInput id="fieldthree" change="doubleService.double(fieldthree.text)" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultthree" /> </mx:HBox>

While this won't generate any errors, the the result handler is hard coded to update resultone. Hence the problem. So here is where a little knowledge can be a dangerous thing. I knew that Flex supported something called an AsyncToken. This is a little magical fairy that creates state for your asynchronous call. Magical may not be exactly right - but I had worked with them a bit in the past so I had a basic idea of how they could work. I whipped up a quick demo that was very jQuery related. Hopefully you will see how:

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">

<mx:RemoteObject destination="ColdFusion" source="flextest" id="doubleService"> <mx:method name="double" /> </mx:RemoteObject>

<mx:Script> <![CDATA[ import mx.rpc.AsyncToken; import mx.rpc.Responder; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent;

public function handleFault(evt:FaultEvent):void { mx.controls.Alert.show(evt.toString()) }

public function handleResult(evt:ResultEvent):void { resultthree.text = evt.result.toString() }

public function getDouble(name:String):void { var field:mx.controls.TextInput = this["field"+name] var resfield:mx.controls.TextInput = this["result"+name] var val:String = field.text var token:AsyncToken = doubleService.double(val) token.addResponder(new mx.rpc.Responder(function(evt:ResultEvent):void { resfield.text = evt.result.toString()}, handleFault)) }

]]> </mx:Script>

<mx:VBox>

<mx:HBox> <mx:Text text="Field One" /> <mx:TextInput id="fieldone" change="getDouble('one')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultone" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Two" /> <mx:TextInput id="fieldtwo" change="getDouble('two')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resulttwo" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Three" /> <mx:TextInput id="fieldthree" change="getDouble('three')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultthree" /> </mx:HBox>

</mx:VBox> </mx:Application>

Ok, a lot going on here. Let's tackle it bit by bit. First, I've simplified my mx:method tag to just contain a name. Right now I guess it's pretty useless. I've written a new function, getDouble, that my fields call. Notice that each field passes a name ("one", "two", "three"). Within getDouble I use this name to get the field I want to work with. I then get the result field as well. Both of these lines....

var field:mx.controls.TextInput = this["field"+name] var resfield:mx.controls.TextInput = this["result"+name]

reminded me of $("#..") calls in jQuery. Or at least a document.getElementById call. I create an AsyncToken and then create an anonymous function to create a dynamic handler for the result. You can see how I passed in the result field to the handler. This then lets any of my three fields run the call and get the result in the right place.

So it "works" - but here is where someone with a little bit more knowledge than I (ok, a lot more) comes along and makes things much more simpler. I ran my code by Simeon Bateman and he pointed out that you can assign any custom data to the token itself. What does that mean? Check out this version:

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">

<mx:RemoteObject destination="ColdFusion" source="flextest" id="doubleService"> <mx:method name="double" result="handleResult(event)" fault="handleFault(event)" /> </mx:RemoteObject>

<mx:Script> <![CDATA[ import mx.rpc.AsyncToken; import mx.rpc.Responder; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent;

public function handleFault(evt:FaultEvent):void { mx.controls.Alert.show(evt.toString()) }

public function handleResult(evt:ResultEvent):void { trace(evt.token.fieldName) var resfield:mx.controls.TextInput = this["result"+evt.token.fieldName] resfield.text = evt.result.toString() }

public function getDouble(name:String):void { var field:mx.controls.TextInput = this["field"+name] var val:String = field.text var token:AsyncToken = doubleService.double(val) token.fieldName = name }

]]> </mx:Script>

<mx:VBox>

<mx:HBox> <mx:Text text="Field One" /> <mx:TextInput id="fieldone" change="getDouble('one')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultone" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Two" /> <mx:TextInput id="fieldtwo" change="getDouble('two')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resulttwo" /> </mx:HBox>

<mx:HBox> <mx:Text text="Field Three" /> <mx:TextInput id="fieldthree" change="getDouble('three')" /> <mx:Text text=" doubled is " /> <mx:TextInput id="resultthree" /> </mx:HBox>

</mx:VBox> </mx:Application>

I've restored the result/fault handlers back to my method tag. Now when I run getDouble, I just assign the name to the token itself. What's cool then is that in the handler, it's set into a token value of the event object. It just. Plain. Works.

Hopefully this is helpful to others (and if not, I sure as heck learned something).