ColdFusion, jQuery and Search Example

This post is more than 2 years old.

I wrote a few sample applications for my jQuery presentation yesterday that I wanted to explore a bit deeper in a blog post. I think search is a great place for Ajax to help out. How can we build a search interface using jQuery and ColdFusion? Let's start with a simple example.

First I'll create a simple form with just a tiny bit of jQuery:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Untitled Document</title> <script src="../jquery.js"></script> <script>

$(document).ready(function() { $("#searchForm").submit(function() { //get the value var search = $("#searchText").val() if($.trim(search) == '') return false $.get('search.cfm',{search:search}, function(data,status) { $("#results").html(data) }) return false }) });

</script>

</head>

<body>

<form id="searchForm"><input type="text" id="searchText" /><input type="submit" value="Search" /></form>

<div id="results"></div>

</body> </html>

Reading from the bottom up, you can see a simple form with one text field. The jQuery code handles taking over the submit action for the form. I first grab the value of the form field and then do a trim() on it. (Trim is something ColdFusion developers are used to and exists as a utility method in jQuery.)

The actual Ajax portion is done with the get call. The first argument is the code I'm going to hit: search.cfm. The second argument is a structure of name/value pairs. In this case I'm passing an argument named search and using the value from the form. The last argument to the get function is my call back, or, 'what to do when done'. In this case, I'm simply taking the results and stuffing it into the DIV with the ID of "results".

So to translate all of this into English: Get the form field. Pass it to search.cfm. Paste the result onto the page.

The ColdFusion code is trivial:

<cfparam name="url.search" default="">

<cfif len(trim(url.search))> <cfset url.search = trim(htmlEditFormat(lcase(url.search)))>

&lt;cfquery name="getArt" datasource="cfartgallery"&gt;
select	artname, description, price
from	art
where	lower(artname) like &lt;cfqueryparam cfsqltype="cf_sql_varchar" value="%#url.search#%"&gt;
or		description like &lt;cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="%#url.search#%"&gt;
&lt;/cfquery&gt;

&lt;cfoutput&gt;
&lt;p&gt;
Your search for #url.search# returned #getArt.recordCount# result(s).
&lt;/p&gt;
&lt;/cfoutput&gt;

&lt;cfoutput query="getArt"&gt;
&lt;p&gt;
&lt;b&gt;#artname#&lt;/b&gt; #dollarFormat(price)#&lt;br/&gt;
#description#
&lt;/p&gt;
&lt;/cfoutput&gt;

</cfif>

I don't have much much going on here. I do some simple validation to ensure a search term was passed. If so, I do the query and just output the results. The CFM handles both the search and display of results.

Let's kick it up a notch. What if we wanted a more advanced search page? Here is a new version of the search page:

<cfquery name="mediatypes" datasource="cfartgallery"> select mediaid, mediatype from media </cfquery>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Untitled Document</title> <script src="../jquery.js"></script> <script>

$(document).ready(function() { $("#searchForm").submit(function() { //get the value var search = $("#searchText").val() if($.trim(search) == '') return false var type = $("#mediatype option:selected").val() $.post('search2.cfm',{search:search,mediatype:type}, function(data,status) { $("#results").html(data) }) return false }) });

</script>

</head>

<body>

<form id="searchForm"> <input type="text" id="searchText" /> <select name="mediatype" id="mediatype"> <option value="">Any Media Type</option> <cfoutput query="mediatypes"> <option value="#mediaid#">#mediatype#</option> </cfoutput> </select> <input type="submit" value="Search" /></form>

<div id="results"></div>

</body> </html>

What's different here? On top I did a quick query to get all the media types from the cfartgallery datasource. Once I have this data, I can use it in a select tag within the form (at the bottom of the code listing above). Now users can search both for a keyword and a keyword and a type of media.

The jQuery code changed a bit as well. Now I also get the selected value from the drop down and pass it in the Ajax call. Notice I switched to post as well. No real reason. In general I almost always prefer Post calls. I'm not going to post the code for search2.cfm as the only change was to look for and notice the mediatype value. (I'm including all of this in a zip attached to the blog entry though.)

Ok, one more example. In the previous two listings, ColdFusion handled running the search query as well as displaying the results. How about making this simpler? I'll just show the jQuery code for my third example since that's the only thing I'm going to change:

$(document).ready(function() { $("#searchForm").submit(function() { //get the value var search = $("#searchText").val() if($.trim(search) == '') return false var type = $("#mediatype option:selected").val() $.getJSON('art.cfc?method=search&returnFormat=json&queryformat=column',{term:search,mediatype:type}, function(result,status) { //console.dir(result)
			var str = ''
			for(var i=0; i &lt; result.ROWCOUNT; i++) {
				str+= '&lt;p&gt;&lt;b&gt;'+result.DATA.ARTNAME[i]+'&lt;/b&gt; $'+result.DATA.PRICE[i]+'&lt;br /&gt;'
				str+= result.DATA.DESCRIPTION[i]+'&lt;/p&gt;'
			}

			$("#results").html(str)

		})
	return false
})

});

So the first few lines are the same - notice the form submission, get the values, etc. Note that I've switched my Ajax call to getJSON. This let's jQuery know that I'll be calling something that returns JSON data. jQuery will handle converting the JSON for me into real JavaScript data.

Notice the URL I'm posting too:

art.cfc?method=search&returnFormat=json&queryformat=column

This is a CFC I've built to handle the search logic for me. I've passed returnFormat to tell ColdFusion to automatically convert the result into JSON.

A quick side note: I have both search parameters (term and mediatype) and url parameters (method, returnFormat, queryFormat). Could I mix them up differently? Yes. I could have used no URL parameters at all and put them all with the {}s in the second argument. I could have used an empty {} and put everything in the URL (with proper escaping of course). In my opinion, the form I used makes the most sense. I've kept the 'meta' stuff (how the request works) in the URL, separate from business logic params used in the second parameter.

Because I'm getting JSON back, I have to handle formatting the result myself. I worked with the result data to create a string and then simply set it to the results div using the html() function. How did I know how to work with the JSON data? Trust me, I had no idea. See this line?

//console.dir(result)

I removed the comments before the line and Firebug gave me a nice display of the data. This let me see how things were setup and let me write the rest of the code. Once again, install Firebug!

The CFC isn't too special. Here is the method I used:

<cfcomponent>

<cffunction name="search" access="remote" returntype="query"> <cfargument name="term" type="string" required="yes"> <cfargument name="mediatype" type="any" required="yes">

&lt;cfset var getArt = ""&gt;

&lt;cfquery name="getArt" datasource="cfartgallery"&gt;
select	artname, description, price
from	art
where	(lower(artname) like &lt;cfqueryparam cfsqltype="cf_sql_varchar" value="%#arguments.term#%"&gt;
or		description like &lt;cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="%#arguments.term#%"&gt;)
&lt;cfif len(arguments.mediatype) and isNumeric(arguments.mediatype) and arguments.mediatype gte 1&gt;
and		mediaid = &lt;cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.mediatype#"&gt;
&lt;/cfif&gt;
&lt;/cfquery&gt;

&lt;cfreturn getArt&gt;

</cffunction>

</cfcomponent>

What I love about this is that my CFC has nothing in it related to jQuery, Ajax, JavaScript, JSON, etc. The only clue that there is any Ajax stuff going on is the access="remote" argument. Because the JSON stuff is built into ColdFusion 8, I can write my business logic and use it either in my 'old school' Web 1.0 application or my fancy, multi-billion dollar Web 2.0 site.

That's it. Any questions?

Download attached file.

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 Edward Beckett posted on 4/8/2009 at 5:19 PM

Very Nice ...

Happy Birthday ...

:)

Comment 2 by Javier Izquierdo posted on 4/8/2009 at 8:55 PM

Nice way of Celebrating your birthday... with a triple example. Hope we have many more happy birthdays to Ray!

Comment 3 by Steve Hanzelman posted on 4/8/2009 at 9:43 PM

Dumb question. I haven't ever fiddled with JSON/etc before, so I saw your examples and figured I give it a try.

I dumped everything onto our test box and received no results from the search. When I took a look using Firebug it was throwing a 404 error for the jquery.js template.

What am I missing?

Thanks!

Comment 4 by Raymond Camden posted on 4/8/2009 at 10:06 PM

Err.. this may be kind of obvious - but doesn't a 404 for jquery.js mean jquery.js is missing? It _should_ have been in the zip, if not, grab it from jquery.com, and ensure the code 'addresses' it (points to it) correctly.

Comment 5 by Steve Hanzelman posted on 4/8/2009 at 10:09 PM

Ray,
You are correct in your comment that it was obvious. I wasn't sure if it should have been included in the zip.

Let's put it this way-it wasn't in mine.

Thanks

Comment 6 by Raymond Camden posted on 4/8/2009 at 10:12 PM

That's weird. It should have been in the zip. If you see anything else missing, let me know. I may need to ...

oh wait.

I'm an idiot. I was thinking this blog entry was my presentation blog entry. That had the FULL zip. This entry just had a few files from it specific to the demo here.

Now it makes sense to me!

Sorry about that!

Comment 7 by Steve Hanzelman posted on 4/8/2009 at 10:25 PM

Hi Ray,
To add one obvious dumb comment on top of another...I hit the presentation entry (I watched part of it and will finish it later-very good stuff!) but didn't see the link for the full zip.

Where am I off now?

Comment 8 by Raymond Camden posted on 4/8/2009 at 10:26 PM

After watching (or before, or whatever) the preso, go to the embedded version on the blog entry, or @ SlideSix. Click the SS menu. There will be a button to download the attachment.

Comment 9 by Jim posted on 4/23/2009 at 1:21 AM

Ray,
I hate to even ask a browser compatibility question, but since I work for the government (and they strictly use Internet Explorer) I have no choice. I applied your example above (2nd example) to a form I have and it works beautifully in FireFox. It does nothing in IE. I did some debugging and found out that it is posing the form data and sending some data back, but it's basically a huge....blank. If I change $("#results").html(data) to $("#results").text(data) it will spit out all of the HTML is text form, but for some reason with it set to HTML I get blank results. Ever heard of this? I know IE can be problematic when it comes to DIVs, but I've Googled the hell out of this topic and can't find any love.

Comment 10 by Raymond Camden posted on 4/23/2009 at 1:25 AM

Hmm. jQuery is _supposed_ to just work in IE. Not having a nice IE to tet here, can you try two quick things for me?

First, try making the result html super simple. Just <b>IE SUCKS</b> and see if it works.

Secondly, um, I thought I had two things but I don't.

Comment 11 by Jim posted on 4/23/2009 at 4:32 PM

Firefox returns IE SUCKS, IE returns blank.

Changing html output to text output returns:

<b> IE SUCKS </b>

I just can't seem to figure out what its problem is with HTML. I really appreciate your help.

Comment 12 by Jim posted on 4/23/2009 at 4:45 PM

Just as a side note, if I copy the HTML that it spits out in text format and paste it into a new page under my site's root, it will display it fine with all the proper CSS elements. I'm thinking it has something to do with the DIV, but I'm grabbing at straws at this point.

Comment 13 by Raymond Camden posted on 4/23/2009 at 5:06 PM

Can I see this online anywhere?

Comment 14 by Jim posted on 4/23/2009 at 7:00 PM

I couldn't show the actual code for government security reasons, so I wrote up an example and posted it to the web. I was surprised to find that it worked on both browsers. Completely blew my mind. I moved my real code out to the web root and it also worked both places. I wrote a CSS class specifically for the div I'm dumping the html into, and suddenly everything fell into place. I guess it was just another one of IE's quirky CSS bugs. I really appreciate you taking the time to look at this for me and ultimately leading me to take that actions that helped me figure it out. THANK YOU RAY!!

Comment 15 by Raymond Camden posted on 4/23/2009 at 7:02 PM

No prob. Glad you got it!

Comment 16 by Chuck WWW posted on 7/3/2009 at 4:33 AM

Hi Ray,

I'm looking for the full download of the example above, you mention the presentation page, but I'm not finding it there either. Do you mind posting the zip here? I guess the download link above just as a subset of the files.

Thanks!

Chuck

Comment 17 by Raymond Camden posted on 7/3/2009 at 6:21 AM

Did you try the Download link at the end of the entry?

Comment 18 by Chuck WWW posted on 7/3/2009 at 4:42 PM

>>I was thinking this blog entry was my presentation blog entry. That had the FULL zip. This entry just had a few files from it specific to the demo here.
<<

So for the "presentation blog entry" I went here:
http://www.coldfusionjedi.c...

But maybe I'm just missing it, but don't see the download?

Thanks and Happy 4th!

Chuck

Comment 19 by Raymond Camden posted on 7/3/2009 at 4:44 PM

Oh, on the embed, click the Menu button. It's there.

Comment 20 by Chuck WWW posted on 7/3/2009 at 4:56 PM

Aha! Thank you!

Comment 21 by Seth posted on 3/24/2010 at 6:40 AM

Thanks Ray! I went from jQuery zero to hero in one day following your tutorials and recorded jQuery intro. Appreciate what you are doing for CF developers trying to get their heads around jQuery.

Comment 22 by Raymond Camden posted on 3/24/2010 at 4:31 PM

Glad to help!

Comment 23 by Lee Lacy posted on 7/9/2010 at 2:15 AM

What would it look like if all you wanted was to search a dropdown box alone on one field?

this is what i'm trying, and I can't figure it out:
<cfquery name="getArt" datasource="felony">
SELECT title, text, changesnotes, newnumber, discussion, id, statute.texasnumber, texas.texasnumber, statutename, keyword, link, category, prefix, texadcode, texadlink, chaptertitle, restorerights, licensekeyword
FROM statute INNER JOIN texas
ON texas.texasnumber = statute.texasnumber
where len(form.keyword) and isBinary(form.keyword) and form.keyword gte "aa"> and keyword = <cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="#form.keyword#")>

Comment 24 by Raymond Camden posted on 7/9/2010 at 2:19 AM

Not sure I get what you mean. You want to "search" a drop down field?

Comment 25 by Raymond Camden posted on 7/9/2010 at 2:33 AM

Oh I get what you mean. Right now it REQUIRES you to type something. First get rid of this:

if($.trim(search) == '') return false

Then modify the CFC like so:

where 1=1
<cfif len(arguments.term)>
and (lower(artname) like <cfqueryparam cfsqltype="cf_sql_varchar" value="%#arguments.term#%">
or description like <cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="%#arguments.term#%">)
</cfif>
<cfif len(arguments.mediatype) and isNumeric(arguments.mediatype) and arguments.mediatype gte 1>
and mediaid = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.mediatype#">
</cfif>

I didn't test that - but it should work.

Comment 26 by lee lacy posted on 7/10/2010 at 12:25 AM

I think my question is simpler than that -- I've gotten test3 to work great; it's the addition of this section in search2demo that I can't get to work:

<cfif len(form.mediatype) and isNumeric(form.mediatype) and form.mediatype gte 1>
and mediaid = <cfqueryparam cfsqltype="cf_sql_integer" value="#form.mediatype#">
</cfif>

What would this cfif look like if all I needed was just one field called "keyword"?

Comment 27 by Raymond Camden posted on 7/10/2010 at 12:43 AM

If you just wanted keyword, then that code wouldn't be there at all.

Comment 28 by gita posted on 7/17/2011 at 8:30 AM

Can you send to me this source code,please?
because i want to see demo this..
Thanks

Comment 29 by Raymond Camden posted on 7/24/2011 at 11:09 PM

There is a link to download the code. It's at the end of the main content.

Comment 30 by Sandra posted on 8/7/2012 at 10:06 PM

Hi Ray,

I cannot get it work in IE 8. I see someone else has this problem. I added a CSS to the Div but it still doesn't work. Any ideas? Thanks!

Comment 31 by Raymond Camden posted on 8/8/2012 at 5:31 AM

You have to describe *how* it isn't working - exactly what. You may also want to modify this block:

$.post('search2.cfm',{search:search,mediatype:type},
function(data,status) {
$("#results").html(data)
})

to this:

$.post('search2.cfm',{search:search,mediatype:type},
function(data,status) {
$("#results").html(data)
},"JSON")

where we tell the code that the result is JSON.