My jQuery Autocomplete Mod

Categories: HTML/ColdFusion, Source Code, JavaScript, jQuery

On a recent project I was working on, I needed an "autocomplete" form field that could do both local data array and AJAX lookups. After doing some searching, I came across Dylan Verheul's jQuery Autcomplete plug-in.

This plug-in did a lot of what I needed, but was still missing some of the functionality I required. So, I just modified the library so it worked the way I needed it to. Here's a list of the changes/enhancements I made:

  • Supports local data array (can now use w/out AJAX).
  • Limit dropdown to XX number of results (good for limiting the results to users)
  • Autofill pre-populates text box as you type
  • New findValue() method can be used to programmatically determine if the value in the box is a valid option. (Useful for verifying the text entered is an existing value option.)
  • Dropdown options now correctly re-position themselves on each display (which means they adjust for changing to the DOM)
  • Dropdown box defaults to the width of the input field its attached to (you can manually specify a larger width as well)
  • Better emulates Windows autocomplete boxes (for example: hitting delete and retyping the same box will now bring back the dropdown menu)

  • Miscellaneous bug fixes

See a live example at http://www.pengoworks.com/workshop/jquery/autocomplete.htm.

UPDATE:
jQuery v1.1.1 has a bug in the pushStack() method that causes a weird behavior of the iFrame being populated in the text box when the [TAB] key is pressed. See the following thread on the jQuery Mailing List for more information: http://www.nabble.com/Bug-in-$()-in-jQuery-v1.1.1--t3144910.html#nabble.i8718421. You can either update your jquery.js file or pull out the latest version from the SVN.

Comments

Connor Garvey's Gravatar I was going crazy trying to get this to work on my site. I use floating divs with z-indexes. Because my divs had z-indexes and yours didn't, the suggestion box was appearing below the rest of the items on the site. I added this line to the ".ac_results" item in the css. "z-index: 10000;" That was a high enough number for my site. Maybe there's a "z-index: top;" that would work for every other site? I don't know.
tszming's Gravatar Hello,

Your plugin is great (should be the best autocomplete plugin I found), but it has a little bug when used with the latest version of jquery: iframe codes will appear in the search text box when you hit `tab` while autocompleting.

also, i found that your codes can't be compressed with the dean edward javascript compressor...
Dan G. Switzer, II's Gravatar @Tszming:

This is actually a bug w/jQuery v1.1.1 and not with my code. The problem lies in the jQuery pushStack() method.

See the following post from the jQuery Mailing List for more information:

http://www.nabble.com/Bug-in-$()-in-jQuery-v1.1.1--t3144910.html#nabble.i8718421
tszming's Gravatar Thanks for your good works!
tszming's Gravatar I found bug today...

you can replace the source with my function below, the problem of the original source is: even matchSubset is set to 0, your initialization will turn it into 1 anyway.


jQuery.fn.autocomplete = function(url, options, data) {

   // Make sure options exists
   options = typeof(options) != 'undefined' ? options : {};

   // Set url as option
   options.url = url;
   // set some bulk local data
   options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;

   // Set default values for required options
   options.inputClass = typeof(options.inputClass) != 'undefined' ? options.inputClass : "ac_input";
   options.resultsClass = typeof(options.resultsClass) != 'undefined' ? options.resultsClass : "ac_results";
   options.lineSeparator = typeof(options.lineSeparator) != 'undefined' ? options.lineSeparator : "\n";
   options.cellSeparator = typeof(options.cellSeparator ) != 'undefined' ? options.cellSeparator : "|";
   options.minChars = typeof(options.minChars) != 'undefined' ? options.minChars : 1;
   options.delay = typeof(options.delay) != 'undefined' ? options.delay : 400;
   options.matchCase = typeof(options.matchCase) != 'undefined' ? options.matchCase : 0;
   options.matchSubset = typeof(options.matchSubset) != 'undefined' ? options.matchSubset : 1;
   options.matchContains = typeof(options.matchContains) != 'undefined' ? options.matchContains : 0;
   options.cacheLength = typeof(options.cacheLength) != 'undefined' ? options.cacheLength : 1;
   options.mustMatch = typeof(options.mustMatch) != 'undefined' ? options.mustMatch : 0;
   options.extraParams = typeof(options.extraParams) != 'undefined' ? options.extraParams : {};
   options.loadingClass = typeof(options.loadingClass) != 'undefined' ? options.loadingClass : "ac_loading";
   options.selectFirst = typeof(options.selectFirst) != 'undefined' ? options.selectFirst : false;
   options.selectOnly = typeof(options.selectOnly) != 'undefined' ? options.selectOnly : false;
   options.maxItemsToShow = typeof(options.maxItemsToShow) != 'undefined' ? options.maxItemsToShow : -1;
   options.autoFill = typeof(options.autoFill) != 'undefined' ? options.autoFill : false;
   options.width = typeof(options.width) != 'undefined' ? parseInt(options.width, 10) : 0;

   this.each(function() {
      var input = this;
      new jQuery.autocomplete(input, options);
   });

   // Don't break the chain
   return this;
}
Kevin Chang's Gravatar Excellent work! Exactly what I was searching for!! Is there a link where I can also download the autocomplete_ajax.cfm coldfusion page you're using?

Thank you very much,
Kevin
Dan G. Switzer, II's Gravatar @Kevin:

I've added a link at the bottom to download the autocomplete_ajax.cfm as a text file.

It's pretty simple--you just want the script to spit out a pipe ("|") delimited list separated by new lines. Each line is converted into an array using the pipe delimiter.
Todd Humphrey's Gravatar I'm having some difficulty adding an extra parameter to the url I am calling. I figured out that the GET variable q is the text box value, but I need to pass an ID to the called URL as well. This is what I have so far:
$("#FriendName").autocomplete(
"autofill_friends2.php",
{
delay:10,
minChars:2,
matchSubset:1,
matchContains:1,
cacheLength:10,
onItemSelect:selectItem,
onFindValue:findValue,
formatItem:formatItem,
autoFill:true
}
);
Dan G. Switzer, II's Gravatar @Todd:

You can use the extraParams option to pass in addition URL parameters to pass.

So to pass an ID of 123456, you do the following:

$("#FriendName").autocomplete(
   "autofill_friends2.php",
   {
      delay:10,
      minChars:2,
      matchSubset:1,
      matchContains:1,
      cacheLength:10,
      onItemSelect:selectItem,
      onFindValue:findValue,
      formatItem:formatItem,
      autoFill:true,
      extraParams: {"id": "123456"}
   }
);
Randy Phillips's Gravatar How do the db calls work once a connection is opened? For instance, if I set the minChars:2 and type in Jo, it queries all cities that start with Jo. But what happens as I contitue to type? Is Joh a new db call? And then Johns, another call, and so on? Or is the initial call stored in chache?
Dan G. Switzer, II's Gravatar @Randy,

I sent this reponse to your jQuery mailing list inquiry:
http://groups.google.com/group/jquery-en/browse_fr...
Jens's Gravatar This a great plugin, but I have some problems when the GET response contains special characters (ex. Danish letters OE 0xd8)
These are replaced by ? (question mark) in the list and in the input field. I've tried to set the response to charset ISO8859-1 with no luck. The $("#myInput").val("\xd8"); does display the right character.

Any ideas?
Dan G. Switzer, II's Gravatar @Jens:

I know there is a problem in the makeUrl() when sending special characters that can be fixed with:

function makeUrl(q) {
   var url = options.url + "?q=" + encodeURI(q);
   for (var i in options.extraParams) {
      url += "&" + i + "=" + encodeURI(options.extraParams[i]);
   }
   return url;
};

If this doesn't fix the issue, make sure that both the page where the page where the Autocomplete plugin is and the response page both return the same charset. I'd recommend using UTF-8, just because IE tends to handle special characters better when you use that charset.
Michael Andreas's Gravatar Hi Dan, thanks for this great plugin. I'm having difficulties setting up this plugin for email address autocompletion and I was wondering if you could kindly help.

I'd like to give focus back to the input field and I want the plugin to be able to handle multiple entries (more or less like http://just-tech.blogspot.com/2006/12/jquery-tweak...">anjesh's tweak). How can I achieve these?

Thank you Dan.
Dan G. Switzer, II's Gravatar @Michael:

This version does not support multiple values.

There is an autocomplete plug-in that's been in the works that does:

http://jqueryjs.googlecode.com/svn/trunk/plugins/a...

There are still issues that are being worked on--such as the autocomplete suggestions only work on the last entry (which means you don't get the suggestions if you're editing a 1st or 2nd values if you have 3 values in the field.)

For support for this plug-in, I suggest you post messages to the jQuery Discussion list.
Michael Andreas's Gravatar Dan, thanks much the info. I didn't aware there is an integration effort by Jörn.

Just to be sure, by mentioning the list you mean General Discussion list (http://groups.google.com/group/jquery-en), right? I've hit 404 when I tried to go to the jQuery Plugins List (http://jquery.com/mailman/listinfo/plugins_jquery....).
Dan G. Switzer, II's Gravatar @Michael:

Yes I was referring to the General Discussion List:

http://groups.google.com/group/jquery-en
chez's Gravatar Hi. Thanks for this great plugin!
help with the below issue plz.

$("#location").autocompleteArray(locs);
$("#country").change( function(){
      $.get("http://apps.duppi.com/ajax/", {ac: "gl", cc: $(this).fieldValue()}, function(data){
$("#location").autocompleteArray(data);
)};

I am trying to change suggestions array on #locations input on change of country SELECT element
Dan G. Switzer, II's Gravatar @Chez:

In the current source code, there's no way to update array. Invoking the autocompleteArray() a second time on a field will create a 2nd instance of the plugin on the field--which will cause problems.

You could add a method to update the array (you'll also want to make sure that you call the flushCache() method as well to clear) or you could use the latest mod:

http://dev.jquery.com/browser/trunk/plugins/autoco...

The version at the URL above was re-written by Jörn, with some assistance from myself.

It has a setOption() method which would allow you to update the data key with some new array data.
Soren Beck Jensen's Gravatar @Jens and Dan

I think that Jens had the same issue as me and it was not solved with the above fix. The problem occurs with the returned data. If your server side script for instance returns:

España
Danmark
København

It would be displayed as:

Espa?a
Danmark
K?benhavn

The solution is as follows:

In your server side script encode the output with a function that encodes a string as a URL rawurlencode() if you use php.

Then change the following in autocomplete:

In the function dataToDom change the following lines so they have the unescape() function around them:

if (options.formatItem) {
li.innerHTML = unescape(options.formatItem(row, i, num));
li.selectValue = unescape(row[0]);
} else {
li.innerHTML = unescape(row[0]);
li.selectValue = unescape(row[0]);
}

If you use the autoFill you also need to unescape that like so:

$input.val($input.val() + unescape(sValue.substring(prev.length)));
Stephen Cassady's Gravatar I'm a bit new with JQuery - if I want the value of a hidden form field to be updated with the value of the selected choice, what would be the code I need to use. Thanks in advance.

For example, if Woodstock is selected in the Ajax form, I want to populate the hidden form field with 1059.

Thanks in advance -
Stephen
Dan G. Switzer, II's Gravatar Stephen,

Just look at the code for the example of the "Ajax City Autocomplete". However instead of the following line in the findValue() function:

alert("The value you selected was: " + sValue);

You'd do something like:

$("#hiddenFieldId").val(sValue);

However, you may want to look into the updated Autocomplete code found in the jQuery SVN:

http://dev.jquery.com/browser/trunk/plugins/autoco...
whataboutthis's Gravatar Dan, thank you very much for this code.

I've set it up in my project and it works fine when testing with Firefox. But Internet Explorer refuses to even load the page. Just says "Operation aborted".

Any ideas?
whataboutthis's Gravatar Oops. Okay that was solved easily by putting the autocomplete() call in a function. I'm a newbie to jquery... :)

$(function(){
$('thebox').autocomplete("blah.py");
});
whataboutthis's Gravatar While that worked, it still does not seem to activate on load... I need to tab out to another field, tab back and then it automatically starts working. But when the page loads, and the autocomplete field gets focus, the loading gif shows up but there are no results showing... Any ideas?
Dan G. Switzer, II's Gravatar For help, I'd recommend signing up for the jQuery mailing list:

http://groups.google.com/group/jquery-en

I subscribe to the list and there are many others on the list that can help you out.
Jim Freeze's Gravatar Hi, nice script.

I was wondering if this plugin supported matching ala textmate. That is, as long as the input characters are in the right order, a match is true even if there are skpped characters. For example, if the user had type 'jm', the following would match:

12345 Jim
John Mann
4567 Ajax Money

Thanks
nicolas angot's Gravatar Just a modification for this great autocomplete plugin to avoid the warning about "secured and unsecured element" with SSL in IE6. This is due to a problem with the iframe. You just have to add a src attribute on the iframe element with the location "javascript:false" in the JS.

Before:
if($.browser.msie){
$results.append(document.createElement('iframe'));
}

After:
if($.browser.msie){
var iframe = document.createElement('iframe');
iframe.src="javascript:false";
$results.append(iframe);
}

Thanks
Jim's Gravatar Is there any way to add additional properties when using a local array similar to what you can do with the Ajax calls and the '|' character? I'm making a menu type object, and using only the text inside the links for the autocomplete function to search. I need it to respond with the entire link though so that it is clickable.
Dan G. Switzer, II's Gravatar @Jim:

Just pass in an array of arrays instead of an array of strings. This will operate just like using th pipe symbol (|) to delimit your AJAX calls.
Jacco Deen's Gravatar Great plugin Dan! I would using it for a chained menu, but...

I don't get the result menu after passing a value to a second autocomplete input like #autocomplete2

At #autocomplete1 I use onItemSelect:getFieldValue,

function getFieldValue(li) {
if( !!li.extra ) {
var sValue = li.extra[0];
$("#autocomplete1_hidden").val(sValue);
$("#autocomplete2").val(sValue);
$("#autocomplete2").findValue(); // not correct I think
}
}

Only when I'm using my left cursor at #autocomplete2, then I get results.

Please help!
Dan G. Switzer, II's Gravatar @Jacco:

I recommend you upgrade to the "official" version of the plug-in:
http://dev.jquery.com/browser/trunk/plugins/autoco...
smitha's Gravatar For some reason my code doesn't fire onItemSelect function. Could you please help me?

Following is the code.

$("#control").autocomplete
(
url,
{
extraParams: { propertyoid : property },
delay: 750,
width: 260,
onItemSelect:function(li)
{
alert(123);
},
formatItem:function(data, i, total)
{
return data[0];
},
formatResult:function(data, i, total)
{
return data[0];
}
}
);
Azadi Saryev's Gravatar Hi Dan,
Great plug-in!
One question: how can i programmatically (through some js call) switch the functionality off? is this at all possible? i am trying to add a "turn autocomplete off" functionality to my form, but no matter what i try (removing all added attributes/classes) the autocomplete persists...
is there some switch in the function i am totally missing or is this functionality not there and once an autocomplete is created it can't be destroyed?

Thanks!
Dan G. Switzer, II's Gravatar @Azadi:

There is no way to completely destroy it--at least without modifying the code. You could delete the input element and re-create it, which would remove the behavior.

Add Comment



If you subscribe, any new posts to this thread will be sent to your email address.