Posted in ColdFusion | Posted on 06-29-2009 | 3,349 views
Yaron asks:
I'd like to know what your preference is for using cfajaxproxy. In JavaScript, do you create one global proxy object and reuse it throughout your script? Or do you create a new proxy object within every function that generates a proxy call?
The reason I'm asking is I had multiple concurrent proxy calls that had their callback functions mixed up. Meaning, one functions makes 2 async calls with two separately defined callback functions. Unfortunately, one callback function received the input from another. Weird.
Ah, asynchronous network calls. Life would be a heck of a lot easier if everything was synchronous. Let's dig a bit into what Yaron found in case it doesn't make sense.
First, consider the following CFC that we will use for our Ajax calls:
2
3<cffunction name="goSlow" access="remote" returnType="string">
4 <cfargument name="name" type="string" required="true">
5 <cfset sleep(300 * randRange(1,4))>
6 <cfif arguments.name is "foo">
7 <cfset sleep(200 * randRange(1,4))>
8 </cfif>
9 <cfreturn "Returned from call #arguments.name#">
10</cffunction>
11
12</cfcomponent>
It has one method, goSlow, that runs a randomly slow sleep call, and makes it even longer if foo is passed as an argument. It then returns the argument passed to it.
The front end code for testing will be:
2<script>
3var foo = new testProxy()
4var goo = new testProxy()
5
6function handleResult(r) {
7 console.log(r)
8}
9
10foo.setCallbackHandler(handleResult)
11goo.setCallbackHandler(handleResult)
12
13function runTest() {
14 console.log("Running test....")
15 foo.goSlow('foo')
16 goo.goSlow('goo')
17 console.log('Done with tests')
18}
19</script>
20
21<input type="button" onClick="runTest()" value="Test">
This page makes use of cfajaxproxy to create a proxy calls called testProxy. I created two instances of it and assigned the same callback handler. The callback handler gets the result, but really has no idea who calls it. This is critical. Unless you set up some mechanism to pass in a 'caller' value, then you can't tell what you are responding too. Not only can't we tell which instance of testProxy was used, we can't even tell what method was called.
So given that - what are some good ways to handle it? You could create a different call back handler for each instance. You can even do this inline:
2goo.setCallbackHandler(function(r) { console.log('special '+r)})
This kinda surprised me. I mean I know that this type of function (an anonymous function) isn't jQuery only, but I didn't start using it till I got big into jQuery. Still though, if you want to run N different methods on the proxy CFC, do you really want N different instances?
My guess is probably yes. Given that you may have one main "service" CFC to handle your Ajax calls, you could create different instances for different areas of concern. So for example:
2var pageProxy = new testProxy()
3var cowbellProxy = new testProxy()
Each proxy in the above code sample will worry about different aspects of remote CFC service.
Can anyone else offer some advice here?


what i also usually do, is create a separate proxy for GET calls and POST calls. otherwise after you set request format in one of your function calls to POST, all your other remote calls will keep using POST method (unless you set a method in each and every ajax request), totally screwing up returned data formats...
Azadi
What if I have a cfc named item.cfc and item.cfc contains the methods for deleting an item and checking to see if an item already exists, which I'll call before I try to do a ColdFusion.Ajax.submitForm with the form data used to create or update a new inventory item. My code would probably look something like this (this is pseudo but if someone wants to see true examples that show how to chain functions, etc. I'll post it)...
<cfajaxproxy cfc="cfc.item" jsclassname="proxyItem">
deleteItem = function(){
/*Code to grab the item number they want to delete and probably a js confirm to see if they're serious about deleting the item - if the confirm returns a true then we can call the remote deleteItem function which would check to see if we could delete an item (we don't want to allow deletes if an item has been used on a transaction in our system because that would break our referential integrity)
The cfc will return a boolean telling us whether or not we were able to delete the item*/
var itemID = ColdFusion.getElementValue('itemID', 'editItem', 'value');
var proxyDeleteItem = new proxyItem();
var proxyDeleteItem.setCallbackHandler(deleteItemCallback);
//Error Handler and Caller
}
deleteItemCallback = function(itemDeleted){
//function code here
/*
So if the cfc passes back a true we would tell the user that their delete was a success and we would route them to a new page, like say the item list page or something like that
*/
}
checkForItem = function(){
//function code here will check to see if an item exists
var itemID = ColdFusion.getElementValue('itemID', 'editItem', 'value');
var proxyCheckItem = new proxyItem();
var proxyCheckItem.setCallbackHandler(deleteItemCallback);
//Error Handler and Caller would follow here
}
checkForItemCallback = function(itemExists){
/*If the item exists then flash an alert to let the user know that they need to specify a unique inventory item number, otherwise call the submitForm function, which you guessed it - probably has a callback of it's own!
*/
}
submitForm = function(){
}
submitFormCallback = function(){
}
If you're looking for shortcuts and less typing then you won't find it - about the only thing that I reuse is an error handler.
BTW, @Ray already knows this so I'm not sure why he did it (probably lazy genius syndrome crap) but anyway I'll throw in my two cents in saying that structuring js functions in the manner of
function MyFunctionName(){
}
causes nothing but problems. I know that this is just example code that he's posted but if you're truly going to do a lot of work with remote calls via js they should all be conjured up using
MyFunctionName = function(){
}
Thanks for posting this. I'm always concerned about using just the right amount of resources (even if it's the client browswer's). When my discovery first came to light I switched to a new instance per call. I'm curious, does anyone know, is there a heavy tax on browser resources for each instance?
It would be nice if Adobe created an ASYNC management system (perhaps an array of callback functions) that track remote calls to their assigned call back functions, insuring these problems will never occur.
Thanks,
Yaron
function functionName (arguments) {function body}
over using
functionName = function(arguments) {function body}
The content of both functions is compiled when they're declared in this manner and the second syntax model allows for a function to be a property of an object. In JavaScript a function is most definitely an object. I'll take the syntax that works 100% of the time and I'll take consistency in my code until someone can illustrate a valid reason as to why I shouldn't handle function declarations in this manner.
Um, well, I guess that outside of callbacks in jQuery I don't normally use anonymous functions, so if I know I'm writing in a 'parent' template I just use function x(). I'm not married to it. ;)
[Add Comment] [Subscribe to Comments]