My jQuery Autocomplete Mod
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

Comments
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...
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
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;
}
Thank you very much,
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.
$("#FriendName").autocomplete(
"autofill_friends2.php",
{
delay:10,
minChars:2,
matchSubset:1,
matchContains:1,
cacheLength:10,
onItemSelect:selectItem,
onFindValue:findValue,
formatItem:formatItem,
autoFill:true
}
);
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"}
}
);
I sent this reponse to your jQuery mailing list inquiry:
http://groups.google.com/group/jquery-en/browse_fr...
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?
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.
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.
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.
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....).
Yes I was referring to the General Discussion List:
http://groups.google.com/group/jquery-en
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
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.
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)));
For example, if Woodstock is selected in the Ajax form, I want to populate the hidden form field with 1059.
Thanks in advance -
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...
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?
$(function(){
$('thebox').autocomplete("blah.py");
});
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.
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
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
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.
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!
I recommend you upgrade to the "official" version of the plug-in:
http://dev.jquery.com/browser/trunk/plugins/autoco...
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];
}
}
);
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!
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.