A user pinged me earlier this morning with an interesting issue. His Ajax application wasn't working as expected. He was using jQuery to hit a CFC. Instead of showing you his code, I simplified it a bit which should make the problem a bit simpler to see. Try and figure it out before reading on:
<cffunction name="getTime2" access="remote" returnFormat="json"> <cfset var s = {}> <cfset s.time = now()> <cfset s.name = "Current Time"> <cfreturn serializeJSON(s)> </cffunction>
It's a bit subtle - but the issue is that he mixes both returnFormat and serializeJSON. I've blogged about returnFormat quite a bit. It's one of my favorite features of ColdFusion 8 and it got little press. His use of it here though is not something I normally recommend. You can pass returnFormat as an argument in the request or you can specify it in the method inline as he did. To me - using it inline is a bad idea. Not "bad" bad, but I don't think the CFC should be concerned with its return form. Instead, it should simply handle it's business logic and let the caller ask for a particular format.
Where things go wrong is the serializeJSON. What's happening here is that CF first runs the code of the method (Make a struct, then JSON it), and then it formats the result in JSON. So basically it JSON encodes a string that is already JSON encoded.
If you view this result (*), you can see the result is a bit funky:
"{"TIME":"June, 03 2008 08:20:06","NAME":"Current Time"}"
All those \ should tip you off. If you remove the serializeJSON, you see a result that should look a bit better:
{"TIME":"June, 03 2008 08:20:06","NAME":"Current Time"}
I'd remove both the serializeJSON and the returnFormat. I'd then edit the jQuery code's URL to add returnFormat=JSON.
*Ok, so let me use this blog entry to say once again that 99% of Ajax problems can be solved with a tool like Firebug. Firebug would have let you see the Ajax request and response, and if you were familiar with JSON, it would have been an big clue. It's also a handy way to see times when you forget to turn off CF debugging.
Archived Comments
Thumbs up for FireBug. I don't think I could even build AJAX applications without it. It simply makes work possible.
Ditto. I find the Javascript cfdebug pretty helpful as well.
Thanks for the article: it's saved us a lot of hassle.
By the way, please note that "its" is spelled wrongly in the sentence "with it's return form". "it's" means "it is" or "it has", not "of it".
Believe it or not - I have a degree in English. ;) Fixed. I also changed considered to concerned.
I was talking about that with some folks on Tribe recently actually... about how it feels like I'm constantly noticing other people substituting homonyms or just plain not the word they intended when they're writing up blogs or forum posts. Of course, if you noticed yourself doing it at the time, you would correct yourself before it went out, so it's something that only someone else can notice. Although yourself at a later time also qualifies as someone else. :P I was assured that yes indeed, I do it too.
When you dont specify the serializeJSON, how do you tell the function to return the JSON as a column query format. Like this
returnFormat=json&queryFormat=column
I use that when I want to "tell the CFC to do it via an URL" but how can I do the same thing directly on the CFC file?
<cffunction name="foo" returnFormat="json" queryFormat="column">
Is not good :(
Rual - why would want to? If you want a CFC to always (or by default) return the json, then do it in CFML, use the serializeJSON with the right arg for queryformat. But again though I wouldn't do that. Keep the CFC generic and use the URL params.
Yeah, in fact I have it that way, but I have been playing around with Railo and it appears it doesnt support the URL thing. And when trying to do it via CFML I dont get the same result as CF8
This is a Spry JSONDataset.
If we didn't have the url thing, then I'd do it in the CFC I guess, but I'd build _another_ method. Ie, one core getFoo() method that returns a native CF query, or whatever, and another method for ajax that wraps getFoo(). That's what I'd do in Railo.
I was wondering - is there no way to set the returnformat programatically inside the function?
if (req is JSONP)
arguments.returnformat='json'
else
arguments.returnformat='wddx'
It feels a bit weird that you can send it as an argument but not treat it as one.
Well, you could obviously do this yourself. Use returnformat=plain and then return wddx or json. To me, I don't view returnFormat as an argument, but more as a operator on the function. (But I haven't had my coffee yet so what do I know?)
Ahh... I found it, after a bit more trial and error :)
if (code executed indicates json return)
url.returnFormat="JSON";
else
url.returnFormat="plain";
That will make my life easier. Sometimes it is simply easier to decide on the server what the returnformat should be, but only after you see the request and it's result. For instance if you have the same methods being accessed by both JSONRPC and JSONP.
Heh, that's cheating. That actually works though? I'll do a test here and blog it later today if so (unless you want to blog it). I don't like it - but it's interesting.
Cheating on a computer does not really count as a crime :)
Blog it if you wish, I have no blog. But it works for sure.
Blogged:
http://www.coldfusionjedi.c...
Thanks for sharing this Stefan.