Hi,
It's
amazing what desperation will do...also in a way, sad, that I had to try so long
to get relatively simple functionality to work between CF and Flex. In
almost 10 years or programming, this is easily one of the most frustrating
challenges I've ever encountered. To say there's a lack of documentation
on this subject is a huge understatement.
Enough
venting...so, for any of you struggling CF programmers out there
pounding your head against the wall trying to integrate Flex with CF, here are
the steps (or secrets). Let me just condition my instructions by saying
that I'm not an expert in anyway on J2EE (and definitely not Flex) so I welcome
any feedback. My explanations are from a newbie
perspective.
Also,
I'd like to thank John Zhao of Macromedia, Tom Link's blog (http://tomlink.net/blog/index.cfm?mode=entry&entry=B662BEF9-7E97-A3B0-E3FB286E23BDAA50),
and the users of this forum for helping me a long the way to this
solution.
INSTALLATION AND DEPLOYMENT OF FLEX ON A J2EE
SERVER
Install Flex onto a J2EE server (I use
Websphere). The steps are quite clear and can be found at: http://www.macromedia.com/support/documentation/en/flex/1/install.html.
You need to be a little familiar with the J2EE platform and installing WAR
files.
The
trick here is that in order for CF and Flex to talk, you need to make sure you
create a file in your CF root called 'crossdomain.xml'. It should have the
following statements:
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
CALLING A CFC FROM
FLEX
The
consensus in the Flex community seems to be that using the AMF protocol leads to
the best performance and as such, calling RemoteObjects is the data model
of choice when integrating with CF.
1) Using the RemoteObject tag, call a
CFC
<mx:RemoteObject id="ro"
endpoint="http://gx270dev.net/flashservices/gateway"
source="Model.mUpdate.fx_UpdateAuthorization"
fault="mx.controls.Alert.show(event.fault.faultstring)"
showBusyCursor="true">
<mx:method name="invUpdateAuthorization" result="doResult(event.result)"/>
</mx:RemoteObject>
<mx:RemoteObject>
id:
Identifier of RemoteObject call. Will be called by ActionScript function
below.
endpoint: The Flash gateway is part of CFMX 7 (not sure
about CFMX 6.1). Simply substitute your hostname and the path
/flashservices/gateway.
source: This should be the relative path (separated by
dots instead of slashes) to the CFC you're calling.
fault:
Not entirely sure what this does, but I think it sends event errors to the
debugger which then popup as alerts.
showBusyCursor: Optional. Basically just shows
the little clock while your CFC is being called.
<mx:method>
name:
Name of function in CFC.
result: ActionScript function that will handle the
resultset from CF. The result keyword represents the type of event
returned from Flex.
2) Write ActionScript function to call
CFC
I
decided that the most efficient means to communicate with CFCs was to send
single Arrays of parameters, instead of individual values, but it's your
choice. In this example I've hardcoded them.
ActionScript:
/*The
doClick() function will be called later in your MXML file*/
private function
doClick():Void{
var QueryArray:Array = new Array();
/*Notice that the
queries start at element '0', not 1 as in
CF. */
QueryArray[0] = "jricha";
QueryArray[1] = 99;
QueryArray[2] = "No";
QueryArray[3] = "No";
*/This is a call
to the RemoteObject, its method, and passes the above
query.
ro.invUpdateAuthorization(QueryArray);
}
ro.invUpdateAuthorization(QueryArray);
}
SETTING UP YOUR
CFC
1) Calling the
CFC
You'll
want your CFC to accept the Array and return Array of Structures. In this
example, I call a query and the package the results accordingly to send back to
Flex.
<cfcomponent>
<cffunction
name="invUpdateAuthorization" access="remote"
returnType="Array">
<!--- Create an argument to
accept your Flex array --->
<cfargument name="Input" required="true" type="Array">
<!--- Create array to return
to Flex --->
<cfset var arrResult = ArrayNew(1)/>
<!--- I parsed
the array into single local vars to use in my query
--->
<cfset UserId = input[1] >
<cfset CCode = input[2] >
<cfset CFlag = input[3] >
<cfset COAvailableFlag = input[4] >
<cfset UserId = input[1] >
<cfset CCode = input[2] >
<cfset CFlag = input[3] >
<cfset COAvailableFlag = input[4] >
<!--- Call
query--->
<cfinclude
template="qry_UpdateAuthorization.cfm">
<!--- Loop over query result
and insert each record into an individual structure and append to an
array--->
<cfoutput query="qGetUpdateAuthorization">
<cfset stItem = StructNew()/>
<cfset stItem["Function"] = #qGetUpdateAuthorization.Function#>
<cfset stItem["Description"] = #qGetUpdateAuthorization.Description#>
<cfset arrayAppend(arrResult,stItem)/>
</cfoutput>
<cfoutput query="qGetUpdateAuthorization">
<cfset stItem = StructNew()/>
<cfset stItem["Function"] = #qGetUpdateAuthorization.Function#>
<cfset stItem["Description"] = #qGetUpdateAuthorization.Description#>
<cfset arrayAppend(arrResult,stItem)/>
</cfoutput>
<!--- Return Array to
Flex--->
<cfreturn arrResult/>
</cffunction>
</cfcomponent>
</cfcomponent>
CREATE AN ACTIONSCRIPT FUNCTION TO ACCEPT CFC
RESULTS
1)
There will be a function that accepts the results from the CFC. It
was earlier defined in our Remote Object method:
<mx:method name="invUpdateAuthorization"
result="doResult(event.result)"/>
This
was a particularly confusing aspect to this entire process. Flex needs
values as objects in order to bind them to a datagrid or other components.
As such, we must take our CFC Array and convert it to an array of objects.
There's a lot of talk about ValueObjects, but I don't necessarily understand
them except to the extent that they represent the data returned from a
recordset. I'm sure there's a more elegant process of doing this...but
this works...at least for now...;-)
ActionScrpt:
/* Our
CFC returns our structure of Arrays into the result Array.
*/
private function doResult(result:Array):Void
{
/*
Create a new object */
var UpdateVO:Object = new Object();
var UpdateVO:Object = new Object();
/* Create an
array to house the objects */
var UpdateResult:Array = new Array();
var UpdateResult:Array = new Array();
/*
Loop over result array and populate new array with objects
*/
for(var i=0; i < result.length; i++){
UpdateVO = result[i];
UpdateResult.push(UpdateVO);
}
for(var i=0; i < result.length; i++){
UpdateVO = result[i];
UpdateResult.push(UpdateVO);
}
/* This is Flex magic as far as
I'm concerned, but basically your new array of objects can be assigned to
your Flex component (in this case a datagrid as shown below) and it
automatically puts all the pieces in the right place
*/
UpdatesDG.dataProvider = UpdateResult;
}
UpdatesDG.dataProvider = UpdateResult;
}
SETUP YOUR MXML FILE TO RECEIVE CFC
RESULTS
1) Setup your MXML file to receive CFC
results
Once
you call your CFC and return your recordset(s) to Flex, you'll want to put them
somewhere...most likely in a datagrid. Here's an
example:
<mx:Panel width="100%"
title="Forms">
<mx:DataGrid id="UpdatesDG" width="100%" height="156" wordWrap="true">
<mx:columns>
<mx:Array>
<mx:DataGridColumn headerText="Update Form" columnName="Function"/>
<mx:DataGridColumn headerText="Description" columnName="Description"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
<mx:Button label="Get Records" click="doClick()"/>
</mx:Panel>
<mx:DataGrid id="UpdatesDG" width="100%" height="156" wordWrap="true">
<mx:columns>
<mx:Array>
<mx:DataGridColumn headerText="Update Form" columnName="Function"/>
<mx:DataGridColumn headerText="Description" columnName="Description"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
<mx:Button label="Get Records" click="doClick()"/>
</mx:Panel>
<mx:DataGrid>
id:
Give the tag an ID to identify it with. The above AS, "UpdatedsDG", called
it.
<mx:DataGridColumn>
headerText: Name that will display in the
Header of the column.
columnName: Name of column as returned by
CFC. CASE SENSITIVE.
I
guess that's it. I've included the full code below. I welcome others
to add, edit. perfect these instructions. I just want this to be a
starting point for ColdFusion programmers getting up to speed with Flex.
Flex is a wonderful advancement in technology and I hope we can encourage others
to embrace it by helping explain some of the language
"secrets".
Best
of luck,
Darius
CODE
Flex:
<?xml version="1.0"
encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script>
<![CDATA[
private function doResult(result:Array):Void{
var UpdateVO:Object = new Object();
var UpdateResult:Array = new Array();
for(var i=0; i < result.length; i++){
UpdateVO = result[i];
UpdateResult.push(UpdateVO);
}
UpdatesDG.dataProvider = UpdateResult;
}
private function doClick():Void{
var QueryArray:Array = new Array();
QueryArray[0] = "jricha";
QueryArray[1] = 99;
QueryArray[2] = "No";
QueryArray[3] = "No";
ro.invUpdateAuthorization(QueryArray);
}
]]>
</mx:Script>
<mx:RemoteObject id="ro" endpoint="http://gx270dev.net/flashservices/gateway" source="Model.mUpdate.fx_UpdateAuthorization" fault="mx.controls.Alert.show(event.fault.faultstring)" showBusyCursor="true">
<mx:method name="invUpdateAuthorization" result="doResult(event.result)"/>
</mx:RemoteObject>
<mx:Panel width="100%" title="Forms">
<mx:DataGrid id="UpdatesDG" width="100%" height="156" wordWrap="true">
<mx:columns>
<mx:Array>
<mx:DataGridColumn headerText="Update Form" columnName="Function"/>
<mx:DataGridColumn headerText="Description" columnName="Description"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
<mx:Button label="Get Records" click="doClick()"/>
</mx:Panel>
</mx:Application>
CFC:
<cfcomponent>
<cffunction name="invUpdateAuthorization" access="remote" returnType="Array">
<cfargument name="Input" required="true" type="Array">
<cfset var arrResult = ArrayNew(1)/>
<cfset UserId = input[1] >
<cfset CCode = input[2] >
<cfset CFlag = input[3] >
<cfset COAvailableFlag = input[4] >
<cffunction name="invUpdateAuthorization" access="remote" returnType="Array">
<cfargument name="Input" required="true" type="Array">
<cfset var arrResult = ArrayNew(1)/>
<cfset UserId = input[1] >
<cfset CCode = input[2] >
<cfset CFlag = input[3] >
<cfset COAvailableFlag = input[4] >
<cfinclude
template="qry_UpdateAuthorization.cfm">
<cfoutput query="qGetUpdateAuthorization">
<cfset stItem = StructNew()/>
<cfset stItem["Function"] = #qGetUpdateAuthorization.Function#>
<cfset stItem["Description"] = #qGetUpdateAuthorization.Description#>
<cfset arrayAppend(arrResult,stItem)/>
</cfoutput>
<cfreturn arrResult/>
<cfoutput query="qGetUpdateAuthorization">
<cfset stItem = StructNew()/>
<cfset stItem["Function"] = #qGetUpdateAuthorization.Function#>
<cfset stItem["Description"] = #qGetUpdateAuthorization.Description#>
<cfset arrayAppend(arrResult,stItem)/>
</cfoutput>
<cfreturn arrResult/>
</cffunction>
</cfcomponent>
</cfcomponent>
--
Flexcoders Mailing List
FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
Search Archives: http://www.mail-archive.com/flexcoders%40yahoogroups.com
SPONSORED LINKS
| Web site design development | Software design and development | Macromedia flex |
| Software development best practice |
YAHOO! GROUPS LINKS
- Visit your group "flexcoders" on the web.
- To unsubscribe from this group, send an email to:
[EMAIL PROTECTED]
- Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service.

