Posted in jQuery, ColdFusion | Posted on 04-08-2009 | 9,107 views
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:
2<html xmlns="http://www.w3.org/1999/xhtml">
3<head>
4<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5<title>Untitled Document</title>
6<script src="../jquery.js"></script>
7<script>
8
9$(document).ready(function() {
10 $("#searchForm").submit(function() {
11 //get the value
12 var search = $("#searchText").val()
13 if($.trim(search) == '') return false
14 $.get('search.cfm',{search:search},
15 function(data,status) {
16 $("#results").html(data)
17 })
18 return false
19 })
20});
21
22</script>
23
24</head>
25
26<body>
27
28<form id="searchForm"><input type="text" id="searchText" /><input type="submit" value="Search" /></form>
29
30<div id="results"></div>
31
32</body>
33</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:
2
3<cfif len(trim(url.search))>
4 <cfset url.search = trim(htmlEditFormat(lcase(url.search)))>
5
6 <cfquery name="getArt" datasource="cfartgallery">
7 select artname, description, price
8 from art
9 where lower(artname) like <cfqueryparam cfsqltype="cf_sql_varchar" value="%#url.search#%">
10 or description like <cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="%#url.search#%">
11 </cfquery>
12
13 <cfoutput>
14 <p>
15 Your search for #url.search# returned #getArt.recordCount# result(s).
16 </p>
17 </cfoutput>
18
19 <cfoutput query="getArt">
20 <p>
21 <b>#artname#</b> #dollarFormat(price)#<br/>
22 #description#
23 </p>
24 </cfoutput>
25
26</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:
2select mediaid, mediatype
3from media
4</cfquery>
5
6<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
7<html xmlns="http://www.w3.org/1999/xhtml">
8<head>
9<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
10<title>Untitled Document</title>
11<script src="../jquery.js"></script>
12<script>
13
14$(document).ready(function() {
15 $("#searchForm").submit(function() {
16 //get the value
17 var search = $("#searchText").val()
18 if($.trim(search) == '') return false
19 var type = $("#mediatype option:selected").val()
20 $.post('search2.cfm',{search:search,mediatype:type},
21 function(data,status) {
22 $("#results").html(data)
23 })
24 return false
25 })
26});
27
28</script>
29
30</head>
31
32<body>
33
34<form id="searchForm">
35<input type="text" id="searchText" />
36<select name="mediatype" id="mediatype">
37 <option value="">Any Media Type</option>
38 <cfoutput query="mediatypes">
39 <option value="#mediaid#">#mediatype#</option>
40 </cfoutput>
41</select>
42<input type="submit" value="Search" /></form>
43
44<div id="results"></div>
45
46</body>
47</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:
2 $("#searchForm").submit(function() {
3 //get the value
4 var search = $("#searchText").val()
5 if($.trim(search) == '') return false
6 var type = $("#mediatype option:selected").val()
7 $.getJSON('art.cfc?method=search&returnFormat=json&queryformat=column',{term:search,mediatype:type},
8 function(result,status) {
9 //console.dir(result)
10
11 var str = ''
12 for(var i=0; i < result.ROWCOUNT; i++) {
13 str+= '<p><b>'+result.DATA.ARTNAME[i]+'</b> $'+result.DATA.PRICE[i]+'<br />'
14 str+= result.DATA.DESCRIPTION[i]+'</p>'
15 }
16
17 $("#results").html(str)
18
19 })
20 return false
21 })
22});
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?
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:
2
3<cffunction name="search" access="remote" returntype="query">
4 <cfargument name="term" type="string" required="yes">
5 <cfargument name="mediatype" type="any" required="yes">
6
7 <cfset var getArt = "">
8
9 <cfquery name="getArt" datasource="cfartgallery">
10 select artname, description, price
11 from art
12 where lowerr(artname) like <cfqueryparam cfsqltype="cf_sql_varchar" value="%#arguments.term#%">
13 or description like <cfqueryparam cfsqltype="cf_sql_lomgvarchar" value="%#arguments.term#%">)
14 <cfif len(arguments.mediatype) and isNumeric(arguments.mediatype) and arguments.mediatype gte 1>
15 and mediaid = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.mediatype#">
16 </cfif>
17 </cfquery>
18
19 <cfreturn getArt>
20
21</cffunction>
22
23</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?


Happy Birthday ...
:)
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!
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
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!
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?
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.
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.
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.
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
<<
So for the "presentation blog entry" I went here:
http://www.coldfusionjedi.com/index.cfm/2009/4/7/j...
But maybe I'm just missing it, but don't see the download?
Thanks and Happy 4th!
Chuck
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#")>
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.
<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"?
because i want to see demo this..
Thanks
[Add Comment] [Subscribe to Comments]