Converting ColdFusion data for jQuery Plugins - An example

This post is more than 2 years old.

Kerrie asks:

A couple of weeks ago, I read a post you wrote on jQuery and form validation... really peaked my interest so I've been taking a look at not only the validation plugin, but many of the other great jQuery plugins... I found this one last night, and its perfect for an app I'm working on, but I cannot figure out how to return the output of a query to populate the list. In the demo they are returning the results of tvshows.php. I noticed a number of other folks were having the same problem but no solution. Might you have a few spare moments to take a look??

Kerrie, don't feel alone. I've noticed this in a few other jQuery plugins. The author will give you an example of the JSON they want, but they don't describe the JSON in pure data forms. So for example, if the JSON string is an array of strings, they don't say that. They just show it and assume you know that is how arrays are represented in JSON. JSON may be easy, but I definitely can't parse it in my head quite yet. Lets take a look at what the plugin wants:

[{"id":"856","name":"House"}, {"id":"1035","name":"Desperate Housewives"}, {"id":"1048","name":"Dollhouse"}, {"id":"1113","name":"Full House"} ]

Ok, so what do you do here? Obviously this is a pattern where every result is {"id":"X", "name":"Y"}, wrapped in [ and ]. So I took a guess here and thought maybe they wanted an array of structs. There is an easy way to test this - just write a quick test script:

s, just a struct: #serializeJSON(s)#
a, just an array: #serializeJSON(a)#
c, an array with a struct: #serializeJSON(c)#

This output:

s, just a struct: {}
a, just an array: []
c, an array with a struct: [{}]

Perfect! So now I know - I need to convert a query into an array of structs. Easy enough, right?

Here is the first CFC method I came up with:

<cffunction name="getNames" access="remote" output="false" returnType="any"> <cfargument name="q" type="string" required="true"> <cfset var entrylookup = ""> <cfset var r = []> <cfset var s = {}>
&lt;cfquery name="entrylookup" datasource="blogdev"&gt;
select	id, title
from	tblblogentries
where	title like &lt;cfqueryparam cfsqltype="cf_sql_varchar" value="%#arguments.q#%"&gt;
&lt;/cfquery&gt;

&lt;cfloop query="entrylookup"&gt;
	&lt;cfset s = {id=id, name=title}&gt;
	&lt;cfset r[arrayLen(r)+1] = s&gt;
&lt;/cfloop&gt;

&lt;cfreturn r&gt;

</cffunction>

The docs said one argument, q, was always passed in, so I look for that and pass it to a query. I then loop over the results and create a struct for each, append it to the array, and return the array.

I next whipped up a quick demo script:

<html>

<head> <script src="/jquery/jquery.js"></script> <script src="/jquery/jquery.tokeninput.js"></script> <link rel="stylesheet" href="/jquery/tokeninput/token-input.css" type="text/css" /> <script> $(document).ready(function() {

$("#name").tokenInput("data.cfc?method=getNames&returnFormat=json", {
	hintText: "Type in the name of a blog entry.",
	noResultsText: "No results",
	searchingText: "Searching..."
})

})

</script> </head>

<body>

<form> <input type="text" name="name" id="name"> </form>

</body> </html>

The code comes from the docs, and me viewing source, for the plugin. As far as I can tell, he doesn't actually document the options, but I was able to guess. So I gave it a try and did it work?

Heck no!

And since it was Ajax and I couldn't see why, I cried into my beer, shut the laptop, and went home.

Oh wait - I have Firebug! And what do I always say when something goes wrong with Ajax? Check Firebug. And guess what - notice the result:

See the case of the ID and NAME values? They are both upper case. I changed my code to use the more verbose struct creation and set the keys so that my case was maintained:

<cffunction name="getNames" access="remote" output="false" returnType="any"> <cfargument name="q" type="string" required="true"> <cfset var entrylookup = ""> <cfset var r = []> <cfset var s = {}>
&lt;cfquery name="entrylookup" datasource="blogdev"&gt;
select	id, title
from	tblblogentries
where	title like &lt;cfqueryparam cfsqltype="cf_sql_varchar" value="%#arguments.q#%"&gt;
&lt;/cfquery&gt;

&lt;cfloop query="entrylookup"&gt;
	&lt;cfset s["id"] = id&gt;
	&lt;cfset s["name"] = title&gt;
	&lt;cfset arrayAppend(r, s)&gt;
&lt;/cfloop&gt;

&lt;cfreturn r&gt;

</cffunction>

And voila - it worked. So long story short - the basic idea is to try to figure out the real data behind the expected JSON - or the real data form I should say. It would have been nice if the author had said "An array of maps" (or whatever PHP uses) though.

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 Phillip Senn posted on 7/3/2009 at 5:01 PM

You have a typo where your fingers autocompleted "real date" when you meant "real data".

Comment 2 by Raymond Camden posted on 7/3/2009 at 5:06 PM

Fixed, thanks.

Comment 3 by Kerrie Whelan posted on 7/6/2009 at 4:22 PM

Ray, now I get it! Thanks so very much for taking the time to work on this. Kerrie

Comment 4 by Kerrie Whelan posted on 7/7/2009 at 12:45 AM

Just one thing I had to add to your example (in case anyone else is trying to get this to work). Inside the loop ... <cfset s=structNew()>

<cfloop query="entrylookup">
<cfset s = structNew()>
<cfset s["id"] = id>
<cfset s["name"] = title>
<cfset arrayAppend(r, s)>
</cfloop>

Thanks again Ray :-)

Comment 5 by Raymond Camden posted on 7/7/2009 at 12:46 AM

Hmm. Why? Are you not on CF8?

Comment 6 by Kerrie Whelan posted on 7/7/2009 at 6:00 PM

CF8 yes. (I am using the Developer's edition for testing). Without adding structNew() my results were repeated.

array
1 struct
id 343618
name Repeated

2 struct
id 343618
name Kelly Repeated

3 struct
id 343618
name Kelly Repeated

Comment 7 by Raymond Camden posted on 7/7/2009 at 11:15 PM

That's odd. The struct has 2 keys, id and name. In each iteration, we overwrite them. Unless its a pointer issue - but I was on CF8 just like you.

Comment 8 by Chris Hampton posted on 7/24/2009 at 1:33 AM

Thanks Ray, this saved me a huge headache.

Comment 9 by Matt Drake posted on 8/6/2009 at 7:24 AM

Hi Ray - thanks for this example! Made figuring out CF to jQuery a lot easier!

I do have to agree with Kerrie above though - if I didn't put structNew() inside of the loop then the one data point was just repeated for each row in the query as opposed to each row's values. I am using CF8 as well. (I was only using the last piece of code you had so I don't have the <cfset r[arrayLen(r)+1] = s> in there).

So the code that worked for me is:
<cfloop query="GetStates">
<cfset gsPoint = structNew()>
<cfset gsPoint["id"] = StateID>
<cfset gsPoint["abbrev"] = StateAbbrev>
<cfset gsPoint["name"] = StateName>
<cfset arrayAppend(gsQry, gsPoint)>
</cfloop>

Thanks!