Using jQuery to post an array to a ColdFusion Component

This post is more than 2 years old.

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.

<cfcomponent>

<cffunction name="handleArray" access="remote" returnType="numeric"> <cfargument name="data" type="array" required="true"> <cfreturn arrayLen(arguments.data)> </cffunction>

</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.)

$(document).ready(function() { var mydata = [1,2,3,4,5,"Camden,Raymond"]; $.post("test.cfc", {method:"handleArray",data:mydata, returnFormat:"plain"}, function(res) { alert($.trim(res)); })

})

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.

$(document).ready(function() { var mydata = [1,2,3,4,5,"Camden,Raymond"]; var myds = serialize(mydata) $.post("test.cfc", {method:"handleArray",data:mydata, returnFormat:"plain"}, function(res) { alert($.trim(res)); })

function serialize(arr) {
	var s = "[";
	for(var i=0; i&lt;arr.length; i++) {
		if(typeof(arr[i]) == "string") s += '"' + arr[i] + '"'
		else s += arr[i]
		if(i+1 &lt; arr.length) s += ","
	}	
	s += "]"
	return s
}

})

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:

<cfcomponent>

<cffunction name="handleArray" access="remote" returnType="numeric"> <cfargument name="data" type="any" required="true"> <cfif isJSON(arguments.data)> <cfset arguments.data = deserializeJSON(arguments.data)> </cfif> <cfreturn arrayLen(arguments.data)> </cffunction>

</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?

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Garrett Johnson posted on 3/24/2010 at 12:48 AM

Depending on what browser's you are trying to support, you could utilize native JSON parsing, which I believe would be easier and faster.

Comment 2 by todd sharp posted on 3/24/2010 at 12:49 AM

Wouldn't jQuery's serializeArray() method work for this?

Comment 3 by Robert Zehnder posted on 3/24/2010 at 12:51 AM

I do not know if it would help in this situation, but Javascript does have a .toSource() method which will return the data from an object.

Comment 4 by Raymond Camden posted on 3/24/2010 at 1:17 AM

@Garret: You misunderstand. I'm not parsing. I'm _creating_ json.

@Todd: Nope, try it - it doesn't return something valid.

@Robert: Interesting, what does toSource return for my array?

Comment 5 by Garrett Johnson posted on 3/24/2010 at 1:30 AM

@ray: oops... I meant native JSON serializing. :-) In this case JSON.stringify should do the trick no? (leaving out support for old browsers of course).

Comment 6 by Raymond Camden posted on 3/24/2010 at 1:32 AM

I must admin - that is new to me. FF 3.5, Chrome, and IE8 only, right? Safari I assume?

Comment 7 by Mike posted on 3/24/2010 at 1:47 AM

Probably not the best way, but I had a similar issue and did a replace in the CFC to eliminate the extra info from jQuery and build it into a list. I then loop it on the CFC side.

Comment 8 by Garrett Johnson posted on 3/24/2010 at 1:56 AM

Hmm got spammed trying to post a cross browser concept....

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.

Comment 9 by Robert Zehnder posted on 3/24/2010 at 3:04 AM

@Ray:

That comes back with a JSON representation of the object. I haven't had a chance to check it though

Comment 10 by Raymond Camden posted on 3/24/2010 at 4:38 PM

Man, it just goes to show you - I need to review a good JS Reference one day. I have no idea what's in the language now. I've got an ORA ref from like 5 years ago - something tells me it is a bit out of date now. ;)

Comment 11 by David McGuigan posted on 3/25/2010 at 4:17 AM

Man the world needs jCFC back!

$.cfcp( "dotpath.to.cfc", "handleArray", { data: arr }, function( r ){ /* Use r immedaitely */ } );

And done.

Comment 12 by Raymond Camden posted on 3/25/2010 at 4:10 PM

Just to be picky - you aren't using r "immediately" - you are using it when the result of the call returns. I'm only being anal here because I know a lot of CFers coming to Ajax for the first time have a hard time with asynchronous behavior.

Comment 13 by Robert Zehnder posted on 3/25/2010 at 4:37 PM

I find myself using synchronous calls more often than async ones. I have gotten in trouble more than once expecting that an async call has already fired and it has not (I'm staring at you $.getJSON())..

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.

Comment 14 by David McGuiganhttp://www.coldf posted on 3/25/2010 at 7:06 PM

I literally tried to respond to this post 6 times just now but every combination of what I wanted to say was flagged as spam. Have I offended the jedi?

Comment 15 by Raymond Camden posted on 3/25/2010 at 7:14 PM

Sorry man - the spam protection can be a bit mysterious at times.

Comment 16 by Eric Hynds posted on 3/30/2010 at 9:51 PM

@Robert - switch back to async and put any logic that requires a response inside the "success" callback. Your users will thank you for it.

Comment 17 by Stephen Duncan Jr posted on 10/22/2010 at 8:56 PM

Sorry for reviving an old post, but I was looking for a better way to deal with this, and I thought I should share what I found.

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.

Comment 18 by Raymond Camden posted on 10/22/2010 at 9:01 PM

Well now that is darn interesting. I hadn't though of using argumentCollection via Ajax. Would you be opposed to me blogging on that later? (In a more general context I mean.)

Comment 19 by Stephen Duncan Jr posted on 10/22/2010 at 9:30 PM

Not at all, please do.

Also, I added this (and my solution) as a question on stack-overflow if anyone has any more thoughts:

http://stackoverflow.com/qu...

Comment 20 by Raymond Camden posted on 11/2/2010 at 6:21 AM

Dude, thank you again: http://www.coldfusionjedi.c...