Async Wait
In my work using Flex 3 with LiveCycle ES, I often have to perform multiple asynchronous calls to the LiveCycle back end upon initialization. I often have to choose whether to invoke these calls concurrently or sequentially.
When executing concurrently, the real chore is synchronizing the results. What if only 2 of the 3 calls succeeded? This can be approached manually by placing flags in your code and checking the state after each result. But that is not a very reusable methodology. What I was really interested in was a class that would perform that function for me, an Asynchronous Wait or Gate class.
Before deciding whether to build my own, I searched the Web to see if anyone else had a solution. I found a lead which led me to the Spicelib AS3 API, and in particular the ConcurrentTaskGroup class. There is also a sibling class called SequentialTaskGroup. Both of these inherit from the TaskGroup class which you can find here.
http://www.spicefactory.org/spicelib/docs/as3/current/api/org/spicefactory/lib/task/TaskGroup.html
I haven’t had a chance to play with it yet, but it looks to provide the basic functionality I was looking for.
Custom Error Tips
I needed a way of alerting the user as they entered information to the fact that they had exceeded the limit of the database field. I’ve always liked the look of the mouse over effects that Flex uses when you use their validation controls. However, using a validator was not acceptable, since I want my alert to be visible as long as the error condition exists, not simply when the mouse hovers of over the control or the user clicks a button to trigger the effect. Anyway , here is my finished result.
I ended up using ToolTipManager to create this. I wrote a change handler for the TextInput like this.
private function OnKeywordChange(event:Event):void {
count.text = (48 - keyword.text.length).toString();
if(keyword.text.length > 48)
{
count_box.setStyle("backgroundColor", 0xff0000);
count.setStyle("color", 0xffffff);
if(error_tool_tip == null)
{
var p:Point = new Point(10, -20);
p = keyword.localToGlobal(p);
p.x = p.x - this.x;
p.y = p.y - this.y;
error_tool_tip = ToolTipManager.createToolTip("Keyword > 48 chars.",p.x, p.y, "errorTipAbove");
}
}
else
{
count_box.setStyle("backgroundColor", 0xffff00);
count.setStyle("color", 0x000000);
if(error_tool_tip != null)
ToolTipManager.destroyToolTip(error_tool_tip);
error_tool_tip = null;
}
}
An interesting side effort of this is how do you handle a ToolTip that you want pointing to a TextInput that is in a Panel that was created via PopUpManager? Remember, the ToolTip is relative to the Application. When the panel moves, the ToolTip doesn’t. I don’t see way of changing this via the ToolTip itself, so I ended up writing a handler for the move event on the Panel. This handler simply mirrors the X,Y changes to the ToolTip.
private function OnPanelMove(event:MoveEvent):void {
if(error_tool_tip != null)
{
error_tool_tip.x = error_tool_tip.x + event.currentTarget.x - event.oldX;
error_tool_tip.y = error_tool_tip.y + event.currentTarget.y - event.oldY;
}
}
Concurrent Asynchronous Calls
When one makes an asynchronous call, does the result return enough information to the event handler to be able to correctly handle any post processing that needs to be done?
As a example, consider you have DataGrid that has a list of documents. Let’s say that you can click on a row and have the system execute a service call that returns some results that you want to display in the results. How do you merge the two?
If you have control over the backend services, you can always inject your query parameters into the result object. What if you don’t have that control?
On way would be to use a global variable to keep track of the query parameters. That’s ok if you can guarantee that the service call won’t be executed multiple times before you can handle the result.
An even better way, that also solves the concurrency issues is to add the data to the token. Here is an example of how I do it.
var token:AsyncToken = ro.invoke(o); token.addResponder(new mx.rpc.Responder(OnInvokeResult, OnInvokeFault)); token["doc_ref"] = _doc_ref; token["doc_number"] = _doc_number;
And then you can pull the data out of the token like this.
private function OnInvokeResult(event:ResultEvent):void {
var doc_number:String = event.token.doc_number;
Alert.show("You requested " + doc_number, "NOTICE");
}
XML Partial Name Matching
I have an XML document in a LC repository that is bound to a ComboBox. Perfect. However, the number of elements in the XML has grown so large that I want to replace the ComboBox with a Filter + Result solution.
E4X clearly provides the ability to filter XML by performing a exact name match, like this
var result:XML = user_data.User.(fullname == "John Johnson")[0];
What if I wanted to perform partial name matchin? Let’s say the user had typed “John”, which should match anyone with John in their first name as well as anyone with John in their last name? I ended up doing it like this. Notice that I convert everything to lowercase to avoid case sensitivity issues.
var result:XMLList = user_data.User.(FullName.toLowerCase().search(user_text.text.toLowerCase()) != -1);