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>
 
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);
 }
 
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] > 
 
    <!--- 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>
 
    <!--- Return Array to Flex--->

       <cfreturn arrResult/>     
 
 </cffunction>
 
</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();
 
/* Create an array to house the objects */
    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);
    }
 
/* 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;
    
   }
 
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: 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: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] >
 
  <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/>     
 
 </cffunction>
 
</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




Reply via email to