Introduction to Flash Remoting
From our current poll on your opinion about Flash Remoting with CFForm, it is clear that most of our readers are excited about it. There are others, however, that either find it too complex or do not know what Remoting is.
I will try to help both groups by explaining what Remoting is and how it can be used.
Flash Remoting is a great Macromedia technology, which has always been on the back, nobody really paying too much attention to it. In Macromedia’s words, “Flash Remoting MX is an application server gateway that provides a network communications channel between Flash applications and remote services.” There is a distinction between the server (the gateway) and the client (the Flash components), but we’ll generalize it as simply “Flash Remoting”.
Basically, it provides a very easy to use method to send data back and forth from Flash to the server. The server can be ColdFusion, which comes with Remoting out of the box, .NET or Java, for which you would need to buy a license, or PHP, by using AMFPHP. I will focus the discussion on the ColdFusion version because I will then talk about Remoting and CFForms.
What it really does is to serialize Flash objects, send them to the server, deserialize them and give them to CF (or the others) in a way they can be natively consumed. It does the same thing the other way around, serializing CF objects, sending them to Flash and deserializing them on the client as Flash Objects. But the benefits do not stop there, as the format used to send the messages, called “AMF” is binary, making the messages much smaller than plain xml. This gives it a performance advantage over Web Services.
For anyone who had to deal with parsing xml on the client, for example, this is bliss. You have a CF array? No problem, send that to Flash, which will see it as nothing more than another array. What about a query, so that we don’t even have to massage the data coming from the database? Sure, Flash will get is as a RecordSet. Mostly everything can be sent back and forth. Is it important to note that what you get on either side is not the same “instance” of the object you are sending. For simple data types this does not really matter, but what matters is that on either side you will have to use the methods and properties native to the language, be it Flash (ActionScript) or CF (CFML). This means that even if you manage to send a complex object (most of the time the gateway won’t allow it), this object will get serialized into a simpler object with only properties, even if you original object had methods. For example, if you send a query from ColdFusion, Flash will see it as a RecordSet. In CF, you have some methods to deal with queries, such as queryAddRow(). That method will not exist in Flash, instead, you will need to find the corresponding method in Flash, such as addItem(). This may seem obvious but it is a really common mistake, mostly when it comes to user-defined classes. No matter how many functions your cfc has, it you send an instance of that cfc to Flash, it will only see an anonymous object with public properties (this.myVariable) and no functions (except for those functions that any Object in ActionScript has).
Each application server has a different implementation of Flash Remoting, as you might expect. But there are also different ways of using remoting within them. With ColdFusion, my preferred method is to use only CFCs. It really makes a very clean implementation: when you need something from the server, you call a CFC function, that will return an object (or void for that matter) of the type specified in the function definition. If I have, for example, a CFC with a function called getCustomers(), I would call myService.getCustomers() in AS code. This is very intuitive.
There are big changes between version 1 and version 2 of remoting, so make sure you are looking at the latest documentation . There are also, just to make it easy, several ways of establishing a connection, and making the call.
As of the version 2.0, the preferred method is by using the Service class. This is an example from MM documentation:
custService = new Service("http://localhost/flashservices/gateway", null, "customerData", null, null); then call a function on the customerData cfc: var pc:PendingCall = custService.getCategories(); // get all categories //define what to do with the call pc.responder = new RelayResponder(this, "onCategoryData", "onCategoryFault" );
where the last two parameters specify the functions to call when the service sends a response or it faults.
This all looks good, but having to create all those objects by “new” makes it a problem if we want to use it in flash forms. Unfortunately, the only workaround (that I have found) is to use the NetServices class, which is deprecated. As always, we are playing with fire when it comes to cfform and the future support of any of these undocumented techniques.
In the cfform, we must first create a connection by:
mx.remoting.NetServices.setDefaultGatewayUrl( "http://www.example.com/flashservices/gateway"); var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection();
or simply:
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection( "http://www.example.com/flashservices/gateway/");
After that we can get an instance of our service, so that we can call several methods on it:
var myService:mx.remoting.NetServiceProxy = connection.getService("path.to.my.cfc", responseHandler );
responsesHandler is a simple object declared as
var responseHandler = {}; responseHandler.onResult = function( results: Object ):Void { } responseHandler.onStatus = function( stat: Object ):Void { }
Each of those functions will handle the results of the remoting call, the first one on success and the second on error.
If we want to call several different methods in our CFC and do different things with the results, then we can declare the handling functions as
responseHandler.myFunction_Result = function( results: Object ):Void { } responseHandler.myFunction_Status = function( status: Object ):Void { }
and then just make the call:
myService.myFunction(parameters);
It really doesn’t take more than a few lines of code to get Remoting up and running. The most difficult part is knowing how to send and receive complex data. I will cover that in the next part of this tutorial, so stay tuned.
But before I go, I wanted to give some information about Remoting and installation issues. ColdFusion comes with remoting out of the box. If everything is properly configured, you shouldn’t have to do anything to get it running. The gateway sits at
http://www.example.com/flashservices/gateway/
However, if you believe that it is not properly installed, you are running IIS and you have access to it, you can check whether there is a virtual directory called JRunScripts in your site definition at IIS. If it is not there, you must create it, pointing it to something like C:\CFusionMX7\runtime\lib\wsconfig\1 (it will be different if you have CF installed in a different directory or if you are running the J2EE version of CF) and give it script and executables permissions. For more info, see this technote: ColdFusion MX: Recommended configuration of multihomed Microsoft IIS web servers
Philippe Maegerman
I've found a very interesting article on MossyBlog on mapping .cfc to .as classes. Have a look it is really good OOP practise http://www.mossyblog.com/archives/516.cfm
Neil Bailey
Jonathan
I did it by adding a column to my query with 1 (checked) or 0 (unchecked), set the value of the cfinput checkbox to {queryname.currentItem.SelectColumn==true} and included a hidden field outside the repeater with a comma delimited list of the ID Column values from the query using ValueList(). Then in my form handler, I can loop over the hidden field and use ListGetAt() to see if it was checked or not. It's a great workaround to this bug
Dennis Hoang
Anyone know of a work around? Any Ideas?
Neil Bailey
How did you differentiate the checkbox NAMES?
Thanks again...
Neil Bailey
Yes, I had this EXACT same issue; it has something to do with changing the dataProvider. The way I worked around it was to access gridName.getItemAt(gridName.selectedIndex)['id_field_name']..
hope this helps...
Jonathan
This was for subscribing/unsubscribing from various available newsletters, so in my case the Checkbox name was "Subscriptions". The submitted form results looked like this: Subscriptions=true,false,false,true,true
That's where the hidden field with the Subscription ID's came in. I used ListGetAt() to match the true/false values of the checkbox fields to the ID numbers of the subscriptions.
Mike
pc.responder = new
can be rewritten as:
pc.responder = {}
This will do the same as new and you don't have to use deprecated code.
I tested this and it works.
-Mike
Philippe Maegerman
var a = new Array()
or var a = []
Neil Bailey
Is there any way that you can pass binary data back/forth between a CFC? I know I can set the returnType to binary, but how would I handle it on the receiving end? We have a page (http://www.staging.healthpro-rehab.com/ria_dashboard.cfm) where we are trying to update our dashboards so that we can change the chart parameters on the fly - right now, we have to rewrite the chart every time, and I know that I can write the binary data directly to the textarea, but how do i access it on the receiving end?
As always - and, I am sure, as is everyone else - I eagerly await your next post..
--nb
PaulH
CyberNaz
Laura
First a question, do your flash forms with data (such as a dropdown with data coming from a query) load at all?
The only problems I've ever had with Flash Remoting not working were due to the virtual folder JRunScripts be missing. I usually add it manually, but running the connectors should fix it too. I recommend that you read this technote on how to set it up:
http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_18307
Lastly, how do you know Remoting is not working? Did you make a test? If you do not see a blank page at flashservices/gateway, it does not mean it is not working.
CyberNaz
Now, here is one more question. In cfgrid-remoting example if have replaced the memberList with my own DB query. I want to pass a variable to my query and want it to produce results based on that. How do I do it rather than just running a simple query?
CyberNaz
srini
312432423
Nahuel
Yes that's true, no refresh it's needed.
Tim
and it doesnt give me a 404 error nor a blank page--it just keeps loading until it times out.
In IIS, I made sure that virtual website has a virtual directory "JRunScripts" that points to the right spot and has Scripts and Exec enabled.
What else do I need to do to get it to work? Driving me crazy. :-)
Tim
myService = connection.getService("path.to.my.cfc", responseHandler );
if I specify the path to my CFC from the webroot. If I specify a path from my CF root, it tells me the "error while calling cfc" message.
That being said, when I attempt to call a method in that CFC with access="remote", nothing happens. (The only thing in this method is a CFFILE action="WRITE" tag to show me that it is even being called, and it is not.) How can I debug where the problem is?
PaulH
Philippe Maegerman
http://server/path/myCfc.cfc?method=myMethod&argument1=HelloWorld ...
This way you can see if it works normally
Philippe
Tim
Mark
I am trying to pass a cfselect box over that has more then 1 value selected. Well when I pass it over only 1 value gets passed. I thought for sure it was because the comma so I did a replace right before I pass it and I still only get 1 value.
var responseHandler = {};
var Type = Type.value.split(",").join("|");
responseHandler.onResult = function( results: Object ):Void {
//when results are back, populate the cfgrid
searchResults.dataProvider = results;
}
responseHandler.onStatus = function( stat: Object ):Void {
//if there is any error, show an alert
alert("Error while calling cfc:" + stat.description);
}
//get service
myService = connection.getService("ssLite", responseHandler );
//make call
myService.getSerchResults(Type);
<cfselect enabled="Yes" name="Type" size="3" label=" Type:" multiple="yes">
<option value="0" SELECTED>All Types</option>
<option value="typea">A</option>
<option value="typeb">B</option>
<option value="typec">C</option>
<option value="typed">D</option>
</cfselect>
Laura
when you have a multiple selection cfselect, the selected items are not stored in a comma delimited list. Instead, the control contains a property called "selectedItems". It is an array and every item contains "data", that is the value you need. You will have to loop over the selectedItems to extract the data. You can either make an array with only the data and send that (the cfc must expect an array) or make a comma delimited list like a normal select. You could try sending the whole selectedItems array, but I am not sure whether it will be accepted it as is.
Mark
Thank you for your time. This site is one of a kind keep up the awsome work.
Seth W
Laura
When you make a Flash Remoting request, the session variables will automatically be passed during the call. You don't need to manually do it. In any case, if you want to have specific variables in your form, add them to hidden fields to avoid recompiling.
Xerrano
Hi, is there any examples on how to load data to a flash-movie-v8 from mysql datasource using coldfusion mx 7.0.1?
It seems that the examples I've been found are out-of-date
none of them work on these versions!
I would thank anyone who likes to share some of knowledge on this matter.
THANKS IN ADVANCE mail: [email protected]
AD
Thank you for the wonderful HowTo.
Within the text you mention:
If we want to call several different methods in our CFC and do different things with the results, then we can declare the handling functions as
responseHandler.myFunction_Result = function( results: Object ):Void {
}
responseHandler.myFunction_Status = function( status: Object ):Void {
}
and then just make the call:
myService.myFunction(parameters);
I wonder if you could provide an example of what you're talking about. I'm having difficulty translating it to real working code.
Thank you.
Laura
Are you using Flash or CFForms?
You can see an example of that in the Real Estate sample app:
http://www.asfusion.com/blog/entry/coldfusion-flash-forms-macromedia-2
Ali Daniali
I'm using CFFORMS. I've torn apart the RealEstate example, but can't seem to figure out how to get two results from two different CFCs to get returned from two seperate action requests (ie. submitResult();submitMetrics;). All I get is the result of the last called function, and the other never appears on the form.
Thanks,
AD
Laura
If you need to call two different CFCs, then you need to have different handlers, something like:
var responseHandler1 = {};
var responseHandler2 = {};
and add the corresponding handler functions to each.
Hope that helps.
Tim
i have a dumb question.
how do i select mulitple options in a cfselect when the multiple flag is true??
i have tried to push the data into the selectedItems array, but that dosnt work.
anybody have a solution?
thanks in advance
tim
Philippe Maegerman
Tim
Thank you that was it.
I never looked in the list component reference section on livedocs for this one, i was in the combo box section.
Thanks again.
Tim
John Barrett
i hoping that I can ask for your help.
How to I set the path to the cfc in flash remoting?
I am not sure I understand the process. When I have it(flashRemotingResponder.cfc) in the cf_webroot no problem, but I want to have a folder to place the cfc in so my webroot does not fill up. I read in another post of yours you called in"com". I tried to make a mapping in the cfadmin, but that was not useful(I get an error). Can you help me with this so I am not confused anymore?
John:)
Laura
Just like web services, Flash remoting services have to be web-accessible. That means you must have the services somewhere in your web root or have a virtual directory (in IIS or the like) pointing there, which makes the directory web accessible. CF mappings will not do the trick because they do not make directories web accessible, they just set up internal mappings that can be used by CF only.
So, from that, the path to the service is just the directory structure from your web root (http://example.com) to the folder where your services are. For example, if you service is called myComponent.cfc and it is in http://example.com/mysite/myservices, then the path would be mysite.myservices.myComponent
That being said, it does not mean you have to have all your components in that folder. From the service component you can call other components using mappings or any other technique you usually use. The service is just a regular component that gets instantiated when the remoting gateway receives the call from Flash.
Hope that helps
John Barrett
Thank you so much for clearning up my confusision:)
I was confused between the mappings, and the actual remoting which now I know are like web services, this clears so much up for me.
Your explantion not only clears this up for me, but teaches me how to call the components too:)
By the way, glad to see the site back on-line`-`
Thanks again for all your help, by you putting so many wonderful examples on your site I feel like I am actually understanding a little, thanks!
John
Jedale
Thanks for the information. Is there any chance that you are going to go into more detail on flash remoting soon?
As for my present situation, I am trying to use flash forms with a few related selects. I would like the form to send the data in the first select to the cfc and then do a query based on what was selected. This cfc would then send the data back to flash and populate the second select box. I have only been able to populate the select with a query independent of the data in the first select. I am having issues sending the data from the form to the cfc and comparing it against the database.
I was wondering if you know of a example online that would do exactly that. I have seen many examples, but none that I have been able to modify to work. I have been looking to no end. I just became aware of flash remoting 's possiblities but I have no idea how to implement it if I can't go through working code. Can you point me in the right direction?
-Jeff
Aleeda
I have a CFC that has a few functions in it. The first function has a query. I want to use the results of the query for the other functions I need to call. Do I return the query results to Flash through Remoting and then call the CFC functions again?
Is there a better way to do this - can I call one CFC function from another one. If so, how do I get the items in the query?
Lesley
Code:
<cfscript>
//make an empty query to prepopulate grid, only needed due to data mask
SearchMaterials = queryNew("PART_NUMBER, DESCRIPTION, MATERIAL_DESCRIPTION, SELECTION_CODE, MIUL_REMARKS, MP_COMMENTS","varchar, varchar, varchar, varchar, varchar, varchar");
</cfscript>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Material Hardware Connector Database</title>
<style >
html, body{
height:100%;
margin:0;
}
body{
background: #202020 url(assets/images/patternBg.gif);
}
#container{
margin: auto;
background: #195075 url(assets/images/background.gif) center center repeat-x;
width: 950px;
border: 1px solid #222;
height: 100%;
}
</style>
</head>
<body>
<table id="container"><tr><td>
<cfform name="MaterialDB" format="flash" width="990" height="600" preservedata="yes" onLoad="initApp()" style="themeColor:##56A1E1; marginRight:-12; background-color:##37749D;">
<cfformitem type="script">
public function initApp():Void
{
MaterialDB.myGlobalObjects = {};
MaterialDB.myGlobalObjects.isEditMode = false;
<!--- set up remoting service --->
setUpRemoting();
<!--- This is telling the columns to wordwrap of the text is larger than field size. --->
var gridMaterial=gridMaterial;
gridMaterial.variableRowHeight = true;
gridMaterial.getColumnAt(2).wordWrap = true;
gridMaterial.getColumnAt(3).wordWrap = true;
gridMaterial.getColumnAt(5).wordWrap = true;
gridMaterial.getColumnAt(6).wordWrap = true;
}
public function setUpRemoting():Void{
<cfoutput>
<!--- create a connection --->
<!--- var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost:8500/flashservices/gateway/");--->
mx.remoting.NetServices.setDefaultGatewayUrl( "http://localhost:8500/flashservices/gateway/");
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection();
<!--- get an instance of our service, so that we can call several methods on it --->
var myService:mx.remoting.NetServiceProxy = connection.getService("MHC.components.ListingGateway", responseHandler );
</cfoutput>
var responseHandler:Object = {};
<!--- put controls in the responseHandler's scope --->
var gridMaterial:mx.controls.DataGrid = gridMaterial;
<!--- handle search by default onResult function --->
<!--- Each of those functions will handle the results of the remoting call, the first one on success and the second on error --->
responseHandler.onResult = function( results: Object ):Void {
gridMaterial.dataProvider = results;
_root.setMode('add');
mx.managers.CursorManager.removeBusyCursor();
}
responseHandler.onStatus = function( stat: Object ):Void {
}
<!--- this function is called when search button is clicked --->
public function submitSearch():Void
{
<!--- get all the search criteria items --->
var searchArguments:Object = {};
<!--- show clock cursor --->
mx.managers.CursorManager.setBusyCursor();
<!--- call service --->
MaterialDB.myGlobalObjects.listingService.search(searchArguments);
}
</cfformitem>
Laura
By a quick glance I don't see any big error that will make the form not to compile. But since your code is so long, it could be anything. You have a couple of unneeded things and you call _root.setMode(), which doesn't exist. Please turn on flash form debugging in your cf administrator to see what the actual error is.
Lesley
What could be wrong? I tried to follow the Real Estate example for my application to implement the remoting. HELP! Can anyone help me? Please!!!!!
Laura
Remoting is not properly installed in your server. See the last paragraph of the post.
vijay
Devon
Thanks for the article.
I am having a problem getting remoting to work. It works fine if I have the cfm file in a subfolder in my wwwroot folder but as soon as I put it in another directory outside of this it stops working, even though it is a virtual directory of a site defined in IIS. The site is not the default site setup by IIS. I have setup a dev site that is on my D: drive so I can match my remote servers directory structure.
Any ideas on how I can get this working for the new site I have defined in IIS?
Thanks. Great site this...
Devon
kamran aslam
plz help me
Alex
I'm using remoting to call CFC methods from a normal flash movie. Basically there are a number of events in the movie that then call the appropriate CFC method, ranging from simply entering the frame to clicking on a button. Realistically, there could be a significant amount of calls -- many of which would be to the same CFC method with slightly different arguments.
My issue is that I'm able to pass data to all my different methods (they are all voids, so no transfer back to Flash) -- but Flash errors out after 2 calls with an "Error opening URL". Always 2 calls, doesn't matter which 2. It'll execute the first, the second, and then the third will always generate the error. I'm officially stumped...no errors or traces on the CF server, and only the one "Error opening URL" error in flash to lead me. Anybody heard of this, experienced something similar or have any suggestions?
Steve
Shawn
Shawn
John Barrett
I have not come across any AS 3 examples either. All I have come across are ways to use AS 2 with flash CS 3. I think(but am most likely wrong) that to use AS 3 with CF Flex 2 is the way.
maybe check out:
http://curiousmindsmedia.wordpress.com/2008/01/29/flash-remoting-as2-vs-as3/
Also, I think that the new cookbook might have be a good read(I am thinking about getting it as well) It seems like they have a chapter dealing with flash remoting, and being a AS 3 book, I would assume that they are using AS 3!
I would assume that using AS 3 would be similar to AS 2 with regards to CF.
Let me know if you get AS 3 remoting working with cfcs I would love to hear about it. I am pretty new to flash remoting,a nd so I might not be the best response.
John
Shawn
John Barrett
I am surprised that the new cookbook does not do a better job. I learn flash with Flash Professional 8 Unleashed and it had a chapter on flash remoting, which was great! Now I have not done much with AS 3, but I would think that if you can connect to the flashgateway, then doing something, such as populating a datagrid with be similar to AS 2. I might be way off on this, but I am a little new at this.
I have some AS 2 remoting code that I can send to you if you want. However, I read that transforming AS 2 to AS 3 code is tricky.
If you do get this working I would love to hear about your adventures with it. I am sure that one of the contacts from MAX could help.
Please send me a mail at [email protected], or use my contact for at http://cfhawaii.com
Shawn
Shawn
John Barrett
I send you a zip at the mail you gave me. It is also at:
http://cfhawaii.com/flash_remoting.zip
there are some examples for making sure you are connected, and a dataGrid example from the definite guide. I would like to see if you can transform it to AS 3, as that will help me when I get flash CS 3.
John
Pitt
how to cheack resutl type?
Saul
All the ways I've found so far of passing variables back to CF from flash seem to involve getURL (and a ? inevitable page refresh?) and loadvariables method in actionscript.
I was trying to use a buytokens (update db balance)/ play the game in flash using tokens/credits in flash game (no db updating) / then cash in in tokens (update db balance), but without a way to force flash to close out if the user navigates away from the page or closes the browser it looks like I would need to have every play in my flash game update the DB. I could live with that if there was a way for flash to send my database updates via CF silently without a page refresh, but I don't know how.
Saul