Simple "FIlter as you type" ColdFusion 8 Demo

I was writing some samples for the new CFWACK and built something short and cute that I thought was worth sharing now. If you look at the search form on ColdFusionBloggers you will see that it does a dynamic replacement on the main content area when you perform a search (if you are on the home page). This is handy but I was curious about other ways of doing it. Consider this simple example:

<form>Search: <input type="text" name="search"><input type="button" value="Search"></form>

<cfdiv bind="url:results.cfm?search={search}" />

The first line is an extremely simple form. The second line is the cool one. I've bound a CFDIV to a results page. By using {search} in the bind, I've set it so that every time the value changes, the contents will change. You can see this in action here:

http://www.coldfusionjedi.com/demos/ajaxsearch/index2.cfm

You can enter a term and either click outside the box or hit the button. (Don't hit Return/Enter.) While that works, an even slicker version is this:

<form>Search: <input type="text" name="search"></form>

<cfdiv bind="url:results.cfm?search={search@keypress}" />

I've removed the button and notice now my bind is based on search@keypress. The @ symbol means I'm defining an event to listen to. Instead of onChange, I've used keypress (when using this format, drop the "on"). Now you get "filter as you type" search, all in 2 lines of code without a line of JavaScript. You can see this demo here:

http://www.coldfusionjedi.com/demos/ajaxsearch

While not the prettiest demo, and not the most elegant (you don't want to type very fast), it's darn tooting sweet how simple the code is. Just in case folks are curious, here is the code for results.cfm. It isn't anything special or "CF8-ish":

<cfparam name="url.search" default=""> <cfset url.search = htmlEditFormat(url.search)> <cfset url.search = left(url.search,255)>

<cfquery name="results" datasource="coldfusionjedi"> select top 10 id, title, posted from tblblogentries where title like <cfqueryparam cfsqltype="cf_sql_varchar" value="%#url.search#%" maxlength="255"> order by posted desc </cfquery>

<table border="1"> <tr> <td>Title</td><td>Posted</td> </tr> <cfoutput query="results"> <tr> <td><a href="http://www.coldfusionjedi.com/index.cfm?mode=entry&entry=#id#">#title#</a></td> <td>#dateFormat(posted)# #timeFormat(posted)#</td> </tr> </cfoutput> </table>

Who here thinks it would be nice to have a list of cool ColdFusion 8 AJAX sites? I don't mean my ugly little demos, but production sites making use of the technology? I'd happily start a list and link to it under Guides.

Archived Comments

Comment 1 by todd sharp posted on 8/3/2007 at 9:10 PM

Maybe Rey Bango could modify GotCFM to accomodate?

http://www.gotcfm.com/theli...

Comment 2 by Rey Bango posted on 8/3/2007 at 9:14 PM

Hey Ray, did you forget about GotCFM?

Comment 3 by Rey Bango posted on 8/3/2007 at 9:15 PM

So, Todd IM's me to show what you're doing and now I'm forced to add it to GotCFM cause your technique is just so darn cool!

Comment 4 by Raymond Camden posted on 8/3/2007 at 9:46 PM

Ah - I was thinking more specific for Ajax examples, but no, gotcfm.com is the right place.

Comment 5 by Nick posted on 8/4/2007 at 3:13 AM

Hey, try typing "update". Notice the case sensitivity when the entry titled "Update...." removes itself.

Just a demo, I know.

Comment 6 by Gareth posted on 8/4/2007 at 6:53 AM

Nice...I especially like the event binding. One thing I would suggest (I know, I know, it's a demo), add autocomplete="off" to the form field so previous entries don't when people are typing in the box.

Comment 7 by Christopher Hester posted on 8/5/2007 at 5:36 PM

On the Function I Set the query only to execute after the passed in string was greater than 3 characters. Works great when searching over a large index.

Comment 8 by Raymond Camden posted on 8/5/2007 at 5:44 PM

Smart idea there.

Comment 9 by Helmut Doll posted on 1/11/2008 at 9:28 PM

In my testing this allows lags one letter behind the text types in the form field (since the keypress event fires before the new letter is part of the form field value).
Using keyup instead fixes this although it would have problems if the key is not released).

Comment 10 by Kas posted on 4/2/2008 at 12:20 AM

I just have to say that I finally got my data to filter thanks to this =^_^= Thank you!!!

Comment 11 by Sam posted on 6/10/2008 at 7:13 AM

Short and Sweet... Got job made my job a lot easier!!!

Comment 12 by AJ posted on 3/27/2009 at 11:11 PM

This doesn't work well for me.

Two huge problems:

1) There is a lazy update. In other words, If I type in a letter, it's as if the keypress event triggers before the letter is entered in the box. So if I type 'D', the keypress event is generated as a blank. If I type 'a' to make the text box appear as 'Da', only the 'D' is submitted to my div page, and so on.

2) The binding event is not compatible with backspaces or pasting.

Any thoughts on these 2 issues?

Comment 13 by Raymond Camden posted on 3/28/2009 at 5:10 PM

AJ:

1) Yep, I think just switching to keyup, instead of keypress, will fix it. I always get those confused.

2) Hmm, then maybe change would do it. (The change event I mean)

I'm planning on doing a blog post like this with jQuery and I'll double check these issues then.

Comment 14 by AJ posted on 3/29/2009 at 12:44 AM

Ray,

I did try the onchange event, and none of the functionality worked. Unless it is 'change', and not 'onchange'. I will try that Monday!

Thanks for your insight always.

AJ

Comment 15 by Raymond Camden posted on 3/29/2009 at 1:02 AM

Yep, all the CF8 binding stuff using an event w/o the "on" in front.

Comment 16 by Chris Ulrich posted on 4/30/2009 at 1:01 AM

Is it possible to have it bind to two events, for example {customerid@keyup,click}

Imagine a customer list, and as you scroll through, a grid below changes with their order history.

Some users use the mouse, others tab around the screen & use the keyboard. As they select, its bound, and the grid changes.

When keyup, its neat - hitting up and down arrows changes the ajax output. With clicking, the keyboard doesn't work. if I do "on change", they have to leave the field.

Any thoughts?

Comment 17 by Raymond Camden posted on 4/30/2009 at 1:06 AM

I don't believe so. Of course, you could always try and tell us what happens. :)

Comment 18 by Chris Ulrich posted on 4/30/2009 at 6:25 PM

Have been trying with no luck ... that's why I was hoping you had an idea :)

Comment 19 by Raymond Camden posted on 4/30/2009 at 9:17 PM

I'd guess not then. If you were using jQuery, you could map both events to the same function.

Comment 20 by Chris Ulrich posted on 4/30/2009 at 9:22 PM

I've heard a lot about jQuery but never worked with it directly. Is this the kind of thing that can be hacked along side the CFTAGS and enhance/modify the BIND functionality, or would jQuery be instead of the CFTags?

Sorry if this is basic ... I've been on CF since CF3, but Ajax is new to me ....

Thanks again

Comment 21 by Raymond Camden posted on 5/1/2009 at 5:56 AM

You can look at CF's Ajax support in two areas (this is a bit vague, but go with me): One is plumbing support and one is front end UI stuff. So switching to jQuery doesn't mean leaving behind all the CF stuff, but you probably won't use any of the front stuff like cfwindow or bindings.

Again, a bit rough, but hopefully it gives you some idea.

Comment 22 by Chris Ulrich posted on 5/7/2009 at 7:53 PM

Got this to work and it was ridiculously easy... just didn't think it through

The original binds were:

bind="cfc:email.showfields({select-field-1},{select-field-2@keypress})"

bind="cfc:email.showfields({select-field-1},{select-field-2@click})"

To get it to listen to both keypress and click all I did was:

bind="cfc:email.showfields({select-field-1},{select-field-2@keypress},{select-field-2@click})"

... and then on the back end CFC I changed:

cfargument name="select-field-1" type="string" required="No" default="0"

cfargument name="select-field-2" type="string" required="No" default="0"

... to ...

cfargument name="select-field-1" type="string" required="No" default="0"

cfargument name="select-field-2" type="string" required="No" default="0"

cfargument name="select-field-dummy" type="string" required="No" default="0"

... works just fine.

Comment 23 by Chris Ulrich posted on 5/7/2009 at 8:13 PM

ONE CORRECTION:

It needs to be "keyup" and not "keypress"

Keypress "lags" ... keyup gets it right

Comment 24 by Adam posted on 7/17/2009 at 11:43 PM

I've been trying to have the results post to a cfgrid with no luck.

I am using this as a client lookup inside a cfwindow. As our staff type the name, the results appear in a cfgrid. Could I be nudged in the direction as to how I may achieve this?

Thanks in advance.

Comment 25 by Adam posted on 7/20/2009 at 11:52 PM

I hammered this out. Thanks for the inspiration!

Comment 26 by Raymond Camden posted on 7/21/2009 at 5:32 AM

Woot, I can take credit for nothing. :>

Comment 27 by Steve Caldwell posted on 11/19/2009 at 7:36 PM

To anyone who may be interested, I just adapted this post to use <cfsearch> and Solr in CF9 rather than a query:

http://bit.ly/QcLik

Comment 28 by Breanna Garrett posted on 6/24/2010 at 6:40 PM

Hey, nice tutorial. :) I know this is totally 3 years old, but I'm working on something that is using CF8.

My problem is: some people hit "enter" and some people click "search". I saw the post about two events on one form...but what event would I use for on "enter"? I can't seem to find anything about that. Any help would be great! :)

Comment 29 by Raymond Camden posted on 6/30/2010 at 1:59 AM

You would need to prevent the enter key from doing a submit. I just did that for the search on RIAForge.

Comment 30 by saiful posted on 7/12/2010 at 9:01 AM

hi ray,
i'm new here. i already try the post above in my application. there some problem with my application. i using the same technique as the post. but after i refresh the cfdiv area with ColdFusion.Window.navigate, the problem occur. i seem that the filter can't use anymore. do u have any idea to troubleshoot the problem?

Comment 31 by Raymond Camden posted on 7/12/2010 at 3:18 PM

Are you saying that if you use the Navigate function to load content into a cfdiv, then it loses the ability to be "bound" anymore?

Comment 32 by saiful posted on 7/13/2010 at 6:32 AM

i'm so sorry with the comment... i just found out that something goes wrong with my code. after i change the target in the navigate from layout id to div id, all going to normal. please forgive me... chill...

Comment 33 by Lisa Walker posted on 10/3/2011 at 6:33 PM

I went to the site you referenced and started typing the word blog. it does not do anything until I press on the search button.
Is this function now disabled?

Comment 34 by Lisa Walker posted on 10/3/2011 at 8:05 PM

it would also be nice if we were able to download your example. Thanks.

Comment 35 by Raymond Camden posted on 10/4/2011 at 5:43 PM

What browser Lisa? Just tested in Chrome and it worked.

As for a download, well, it is only 2 files and the source is above. You can cut and paste. :)

Comment 36 by luke posted on 3/8/2012 at 11:25 PM

If I type characters into the filter quickly - *sometimes* I get a previous result set instead of the final one expected.
ex. if I type say "info 3", the grid will update to selections with "info 3", but then refresh back to "info"
Not always, tho. I wrapped the cfc query in a plain cftransaction but still happens.
Any ideas?

Running cf9.0.1 and MySql latest.

Comment 37 by Raymond Camden posted on 3/9/2012 at 4:57 PM

I'm guessing it is just a network issue/latency between the update and typing too quickly. One could address this by modifying the JS code to NOT do a new search while another one is running, but then your results are behind what you type.

Comment 38 by Luke posted on 3/11/2012 at 11:03 PM

I'm using this for an internal error log. I've switched from filtering as a user types to one input search. One call to db. Thx again for the great example.

Comment 39 by Ian posted on 7/20/2013 at 2:18 AM

What sort of performance hit can you expect with a solution like this?
Lets say you start the search after 3 characters are entered. I am thinking of setting up a search like this against an internal knowledge base which would have multiple agents hitting the search.

Comment 40 by Raymond Camden posted on 7/20/2013 at 2:21 AM

It depends I suppose. I'd worry about how quickly your server can respond.

Comment 41 by Ian posted on 7/20/2013 at 2:34 AM

Thanks for the quick response! Any suggestions on what to check or test? I'd like to know if this going to be any issue up front... if possible

The might be up to 300 unique visits to the search page and some portion of those could be running a search simultaneously.

I know ... pretty vague!

Comment 42 by Raymond Camden posted on 7/20/2013 at 2:37 AM

If you use result=X in your cfquery tag (where X is a variable name), you get data about how long it took to execute. You can log it and see if it seems reasonable (probably <10 ms). Really you need to test and see. :)

Comment 43 by Ian posted on 7/27/2013 at 1:39 AM

Got a POC going and it seems pretty quick. I am using an cfinput with autosuggest using a list of tags, but I am running into a bit of snag

<cfdiv bind="url:planning.cfm?menuID=5055&tag={search@keyup}" />

The bind is not triggers by selecting one of the autosuggest options, the user need to pick and then type something...I need some sort of other event like select or??

Any ideas?

Comment 44 by Ian posted on 7/27/2013 at 1:47 AM

ah.... this works, just bind it!

<cfdiv bind="url:planning.cfm?menuID=5055&tag={search}" />

Comment 45 by Raymond Camden posted on 7/27/2013 at 1:50 AM

Let me just stress that I no longer recommend using these tags. I strongly urge folks to look at other solutions like jQueryUI.