Wednesday, January 19, 2011

Type Ahead Searches with jQuery

I was working on a mobile app and wanted to try a type ahead search to easy the user typing on a phone keyboard. I was able to make the ajax calls using jQuery to get the data, but I ran into some race conditions. As the user typed I made an ajax call but sometimes the first ajax call would take longer than the second. Thus updating the results with the first ajax calls data, because it finished later.

Example:
I starting typing "b". Then it would fire off an ajax call to get all the data with the letter "b".

Next I typed "a". So my search input box looked like this "ba". And firing off another ajax call to get all the data with the letters "ba".

I didn't know this but you can put the ajax request in a variable and kill it. Check it out.

<script type="text/javascript">
var ajaxCall;
typeAheadSearch = function(){
if(ajaxCall != undefined){
ajaxCall.abort();
}

ajaxCall = jQuery.ajax({
url: "http://www.somedomain.com/typeAheadSearch/_results.cfm",
data:{search:jQuery("##search").val()},
success:function(data){
jQuery("##results").html(data);
}
});
};
</script>

I started a variable called "ajaxCall" to store the request in. The first thing I do in the typeAheadSearch() is kill the current request by calling abort(). The next thing that I didn't know you could is that jQuery's ajax() returns the request. This is so handy.

4 comments:

  1. That is a pretty nice feature.

    I usually bind to the keyDown event for the text input and wait about 500ms before firing off the ajax call. That way if they are typing fast it will wait to fire off the call until they have paused for (half) a second.

    ReplyDelete
  2. I didn't think of using the keyDown event with a half second. Good idea.

    ReplyDelete
  3. @Joe:

    While this doesn't address the issue of AJAX requests potentially returning results out of sequence (which is due to its asynchronous nature), one technique that is a big help when doing things on a keyboard event, is to use a "debounce" technique to limit the invoking of your event handlers.

    In most cases, you probably really don't want to trigger off an AJAX request on each keypress. I mean if someone types "coldfu" in 1s, you probably don't really want to trigger off 6 separate requests. More likely you're wanting to trigger off the effect when there's a delay.

    This is were debouncing fills the roll. In a nutshell, debouncing a function prevents execution of a function until it hasn't been called in specified time frame. So, if you debouce a keyboard event to trigger after 500ms, it'll only actual fire once there has been a 500ms delay after the last keyboard event was fired.

    This is great for making sure that you don't unneccesarily keep firing off an event that might not need to run.

    The concept can be a bit hard to digest, but I have an example on my blog:

    http://blog.pengoworks.com/index.cfm/2009/3/24/Managing-JavaScript-eventsfunctions-using-debouncing

    There's also some from John Hann which gives you an easy way to implement debouncing on your events (and functions--it's useful for other things too.)

    ReplyDelete
  4. @Dan

    Nice post. Very good example. I like the prototype objects too. I haven't played much with those yet.

    ReplyDelete