Posted in jQuery, JavaScript, ColdFusion | Posted on 03-23-2010 | 6,430 views
A reader sent in an interesting question today. He was trying to make use of jQuery to post an array of data to a ColdFusion component. His CFC was expecting, and demanding, an array argument. Whenever he fired off the request though he received an error from ColdFusion saying the argument was not a valid array. Let's look at an example of this so it is more clear.
I'll start off with my server side component. It handles the incredibly complex task of returning the size of an array.2
3<cffunction name="handleArray" access="remote" returnType="numeric">
4 <cfargument name="data" type="array" required="true">
5 <cfreturn arrayLen(arguments.data)>
6</cffunction>
7
8</cfcomponent>
On the client side, I'm going to use jQuery to post a static query to the CFC. This will happen immediately on document load so I don't have to bother clicking a button or anything fancy like that. (Note, in the code block below I've removed the html, head, and body tags since they are all empty. I do have a script block to load in the jQuery library though.)
2 var mydata = [1,2,3,4,5,"Camden,Raymond"];
3 $.post("test.cfc", {method:"handleArray",data:mydata, returnFormat:"plain"}, function(res) {
4 alert($.trim(res));
5 })
6
7})
So, what would you expect to happen here? Well first off, it is important to remember that we are talking about an HTTP post here. You cannot send a complex data type of POST. It must be encoded somehow. jQuery does indeed encode the data - just not how you would expect it. Upon running this and examining the POST data in my Chrome dev tools, I see the following:

Not what you expected, right? You can see why ColdFusion complained. The "Data" argument doesn't exist. Instead we have a lit of things named like Data, but not quite. You can try using toString on the array, but that doesn't correctly handle the comma in the data. So what to do?
What I recommended was converting the array to JSON. It always surprises me when I remember that jQuery can't produce JSON on its own, but there are plugins out there that will do it it for you. Because JSON is a string format though I thought I'd write up a quick function to generate the string for me. This function makes the assumption that are array only contains simple values of numbers and strings.
2 var mydata = [1,2,3,4,5,"Camden,Raymond"];
3 var myds = serialize(mydata)
4 $.post("test.cfc", {method:"handleArray",data:mydata, returnFormat:"plain"}, function(res) {
5 alert($.trim(res));
6 })
7
8 function serialize(arr) {
9 var s = "[";
10 for(var i=0; i<arr.length; i++) {
11 if(typeof(arr[i]) == "string") s += '"' + arr[i] + '"'
12 else s += arr[i]
13 if(i+1 < arr.length) s += ","
14 }
15 s += "]"
16 return s
17 }
18})
As you can see, I wrote a serialize function to handle converting the array into a JSON-encoded array. This isn't the only change though. We still aren't sending an array to the CFC. It's a string. So I rewrote the CFC to handle it a bit better:
2
3<cffunction name="handleArray" access="remote" returnType="numeric">
4 <cfargument name="data" type="any" required="true">
5 <cfif isJSON(arguments.data)>
6 <cfset arguments.data = deserializeJSON(arguments.data)>
7 </cfif>
8 <cfreturn arrayLen(arguments.data)>
9</cffunction>
10
11</cfcomponent>
I normally don't like to "muck" up my code so that it has outside knowledge like this. However, I'd probably have a remote service component in front of this component anyway and the whole issue would become moot.
There are probably many better ways of handling this. Any suggestions?


@Todd: Nope, try it - it doesn't return something valid.
@Robert: Interesting, what does toSource return for my array?
Ideally you could check and see if the JSON property is defined within the window object, if not utilize jQuery's $.getScript to load the json2 lib by Douglas Crockford, otherwise it will use the native one (faster).
But ie8, ff3.5, and webkit support it natively.
That comes back with a JSON representation of the object. I haven't had a chance to check it though
$.cfcp( "dotpath.to.cfc", "handleArray", { data: arr }, function( r ){ /* Use r immedaitely */ } );
And done.
I haven't seen the $.cfcp project and it doesn't look like I will ever see it, but I am comfortable with calling things the old-fashioned way.
By looking at the HTTP calls made when using cfajaxproxy, I discovered that you can send a single argumentCollection parameter as a JSON string to call the remote CFC method.
So the client side call looks something like this (using jquery-json plugin to do the serialization):
var params = {data: ['a', 'b', 'c']};
$.post('test.cfc', {method:"handleArray", returnFormat:"plain", argumentCollection: $.toJSON(params)}, function(res) {
alert($.trim(res));
});
The benefit here is that there's no change to the CFC.
Also, I added this (and my solution) as a question on stack-overflow if anyone has any more thoughts:
http://stackoverflow.com/questions/3999283/how-can...
[Add Comment] [Subscribe to Comments]