Twitter: raymondcamden


Address: Lafayette, LA, USA

Using jQuery to post an array to a ColdFusion Component

03-23-2010 10,871 views jQuery, JavaScript, ColdFusion 20 Comments

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.

view plain print about
1<cfcomponent>
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.)

view plain print about
1$(document).ready(function() {
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.

view plain print about
1$(document).ready(function() {
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:

view plain print about
1<cfcomponent>
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?

20 Comments

  • Commented on 03-23-2010 at 3:48 PM
    Depending on what browser's you are trying to support, you could utilize native JSON parsing, which I believe would be easier and faster.
  • Commented on 03-23-2010 at 3:49 PM
    Wouldn't jQuery's serializeArray() method work for this?
  • Commented on 03-23-2010 at 3:51 PM
    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.
  • Commented on 03-23-2010 at 4:17 PM
    @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?
  • Commented on 03-23-2010 at 4:30 PM
    @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).
  • Commented on 03-23-2010 at 4:32 PM
    I must admin - that is new to me. FF 3.5, Chrome, and IE8 only, right? Safari I assume?
  • Mike #
    Commented on 03-23-2010 at 4:47 PM
    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.
  • Commented on 03-23-2010 at 4:56 PM
    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.
  • Commented on 03-23-2010 at 6:04 PM
    @Ray:

    That comes back with a JSON representation of the object. I haven't had a chance to check it though
  • Commented on 03-24-2010 at 7:38 AM
    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. ;)
  • Commented on 03-24-2010 at 7:17 PM
    Man the world needs jCFC back!

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

    And done.
  • Commented on 03-25-2010 at 7:10 AM
    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.
  • Commented on 03-25-2010 at 7:37 AM
    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.
  • Commented on 03-25-2010 at 10:06 AM
    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?
  • Commented on 03-25-2010 at 10:14 AM
    Sorry man - the spam protection can be a bit mysterious at times.
  • Commented on 03-30-2010 at 12: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.
  • Commented on 10-22-2010 at 11:56 AM
    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.
  • Commented on 10-22-2010 at 12: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.)
  • Commented on 10-22-2010 at 12: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/questions/3999283/how-can...
  • Commented on 11-01-2010 at 9:21 PM
    Dude, thank you again: http://www.coldfusionjedi.com/index.cfm/2010/11/1/...

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty