AutoSuggest: An AJAX auto-complete text field

Posted on August 04, 2006

Update 2007-02-07

Lots of changes. Demo and documentation here.

Download AutoSuggest v.2

Tested on Safari 2.0.4, Firefox 2 Mac & PC, IE 6, IE 7

Update 2006-11-17

Added support for special characters.

Original post 2006-08-04

I finally got around to making a re-usable AJAX auto-suggest field. Here it is in action.

The AutoSuggest class adds a popdown menu of suggested values to a text field. The user can either click directly on a suggestion to enter it into the field, or navigate the list using the up and down arrow keys, selecting a value using the tab key. The values for the suggestion list are to provided as XML (by a PHP script, or similar).

Version history

2007-02-07 : 2 : Lots of changes. See documentation.

2006-11-17 : 1.2 : XHTML compatible. (Thanks to Lapinbleu.)

2006-09-20 : 1.1 : Added special character support.

2006-08-04 : 1.0 : First release.



Comments (105)

Jeffrey Ropp said

Nicely done. For some reason, my results dont appear within a scroll area? I copied most of your CSS and still can't get it to work.

I've also found that my results aren't always qualified by the first character provided. You are welcome to test with my sample data: http://www.zoyzoy.com/cellphoneservicereport/phones.php

Try an "S" first.

Any thoughts would be appreciated!

Thanks,
Jeff

Posted by: Jeffrey Ropp at August 14, 2006 11:39 AM .

Robert said

Very interesting.
I still have a question.
Can i use this example for a site that needs more than 1 autosuggest field on the same page ?
I have several fields that need auto-completion.
Thanks for a response

Posted by: Robert at August 14, 2006 03:40 PM .

test said

test

Posted by: test at August 15, 2006 04:20 PM .

Rebecca said

This is great! Almost exactly what I needed.

I'm working on tweaking things a bit to get it to respond better with larger sized arrays (4000). Thinking maybe it's just not meant to be and I should break my array up into smaller chunks grouped by initial character(s). Anywho, if you happen to have any recommendations on improving performance along those lines, they'd be more than welcome!

Cheers and thanks for sharing your work!

Posted by: Rebecca at August 27, 2006 12:09 AM .

bsn said

Hi. I've been on holiday for two weeks, and haven't been able (or willing) to check my mail.

@Jeff:
Your example doesn't seem to be working. What browser are you using?

@Robert:
Autosuggest is object-orientated. You can create as many instances of it as you like on one page.
var as1 = new AutoSuggest('input1', options);
var as2 = new AutoSuggest('input2', options);
Obviously you would want to have different options objects for the individual textfields.

@Rebecca:
4000! The whole idea is to select results according to the initial characters, not to return everything in the database. Even so, I would limit the number of results returned to about 50, using a mySQL LIMIT clause. No user is going to scroll through 4000 options, and the AJAX response time will be markedly slower loading an XML file of that size (XML is notoriously verbose).

Posted by: bsn at August 30, 2006 09:37 AM .

Jamie said

Great script - very clearly written article as well. After spending most of the afternoon trying to find a part solution to my needs this fitted the bill very well.

One thing I do need to do however is to be able to pass a second bit of information, for example an id of a country code, so that the form can then be processed using that instead of the viewable name. Do you think that is possible within your framework?

It would also be neat to have a message asking for more input to meet Rebecca's needs to show either "Too many matches, enter more characters", or "No matches".

Hope you had a great holiday.

Posted by: Jamie at August 31, 2006 06:13 PM .

bsn said

@Jamie:

It is of course possible to pass more information in the response to the request.

However, an autosuggest field is meant to be an unobtrusive enhancement to the user experience: the form should still be usable without the javascript. If your form processing script is expecting a numeric id that is linked to a particular country, a user without javascript has no means of knowing that number, and you script won't know what to do with the input.

Let the form pass the field value as a string, and try and map it to an ID server-side.

Another point: If you want a numeric id, you are probably expecting one of a discrete range of already existing values. The autosuggest technique is widely used where a user may select one of a range of values, but can also enter a completely new value (eg. search terms at google suggest). If you want to ensure that the user selects one of a predefined range of values, I would consider using an html select element.

Hmm... but what if you have 3000 predefined values? Way too many for a select element...

Then you could use autosuggest and add a "No Matches" message as you suggested, and only enable the submit button when the user has chosen a valid value. (Of course, you would still have to check the value server-side in case the user has deactivated javascript). But you would have to rewrite the script a bit... :)

And I did have a nice holiday. Thanks for asking.

Posted by: bsn at August 31, 2006 06:37 PM .

Jamie said

Found a small issue with the parameters you pass.
If you set minchars to anything other than 1, while it is great at ensuring you have enough content to trigger a search in the first place, it also prevents the script being reinitialised should you make a mistake and delete a character. Effectively you would have to delete 3 and then reenter them in order to see the script running again.

Worth a small rething?

Posted by: Jamie at August 31, 2006 10:36 PM .

Jamie said

Timothy,

Your responses make a lot of sense - I hadn't really thought about the actual use for predefined values. In the specific application I have in mind I currently use a select, and yes, there are way too many to make it useful, hence the search for autocomplete.

Comments about disabling javascript are also interesting, while the temptation is to simply require javascript, I suppose I could gracefully fall back to a select?

After spending the last few hours with your code (I'm a real js newbie, and this feels like a steep learning curve!), I've managed to get the id parameter passed when using tab, but I'm currently struggling with the onClick event, as it seems to always loop to the end of the array.

For example, search on "abbott" on my demo site you can see the element ids as they are listed in the data. Using tab you will see the valid playerid, but with a mouse event it remains undefined.

Another wee thing is that if you enter the comma (,) it seems to break the matching. I probably need a backslash in there somewhere.

Posted by: Jamie at August 31, 2006 10:58 PM .

bsn said

@Jamie:

I can't seem to replicate the problems you are having. Here's another example similar to what you are trying to do:

http://www.brandspankingnew.net/specials/ajax_autosuggest/jamietest.html

On your demo site, typing "ab" somehow doesn't match "Abbott", although it looks as though it should. Not sure why; possibly a server-side problem.


Tim.

Posted by: bsn at September 1, 2006 10:03 AM .

gb5256 said

Hello BSN,

thank you for this brillant littel program. This is exaclety what i needed: something tiny but very smart.
One question: you mentioned above that it is not possible to work with bigger datasets than 4000. I have already repalces the hardcoded part of test.php to a MYSQL query that gets all the records and puts them in the Array acountries. How can I make it to only query those records where the first letters match?

Posted by: gb5256 at September 6, 2006 03:59 PM .

bsn said

@gb5256

Use a WHERE .. LIKE clause in your MySQL SELECT query to match the first letters.

SELECT sName FROM countries WHERE sName LIKE 'aus%'

The above clause will return all entries in the 'countries' table where the sName field begins with 'aus'.

It is possible to work with datasets larger than 4000. I just meant that it's impractical to put all 4000 entries into an autosuggest pulldown. I would just take the first 20 entries returned using a LIMIT clause.

SELECT sName FROM countries WHERE sName LIKE 'aus%' LIMIT 0,20

Tim.

Posted by: bsn at September 6, 2006 05:29 PM .

gb5256 said

hell bsn,

i totally agree with you. The power of ajax is also the speed, but if I pull more than 4000 records each time, it takes some seconds to react. I will try your solution right now.

Again, thank you very much for your program and for your reply to my question.

gb5256

Posted by: gb5256 at September 7, 2006 08:45 AM .

gb5256 said

Hi out there.
Does anybody who uses this auto-completer has experience with a fuzzy search?
Example:
If I search for "Rosa" the autocomplete could give me not only records starting with Rosa, but also Records that have the letters "rosa" inside?

It would already help me if someone could give me a hint where the code compares the input word with the list. (cant find it in the js-files).
Sorry but this Ajax and java is absolutely new for me. I'm programming only with PHP, but thinking of swithing...

Any hints?

Thanks to everybody who is envolved in this.

Posted by: gb5256 at September 7, 2006 02:11 PM .

bsn said

@gb5256

The matching isn't done by Javascript, but server-side. Otherwise you would be sending unnecessary data that would only be processed and immediately discarded. (Unnecessary overhead.)

The idea is that the server gets the input via javascript/xmlHTTPrequest, retrieves the matching results, and passes only these back to the client. The results are then displayed via javascript.

The whole thing looks like this:

DOM -> Javascript -> XMLHTTPRequest -> Server (PHP/MySQL) -> XML -> Javascript -> DOM

Posted by: bsn at September 7, 2006 02:35 PM .

Nico said

Hello,
In my db I have a table countries with 2 fields: Id and description. If I choose a country I would also to have the id of the country that I have selected, in a hidden field. Any suggestion?
Thanks.

Posted by: Nico at September 9, 2006 07:19 PM .

David said

Hello

I would like to know how could I use special characters, like éáüó... I was looking for the solution but I coldnt find it. It would be very importatnt for me.

Thanks

Posted by: David at September 19, 2006 10:44 PM .

bsn said

@ David

should work with special characters now. Be sure to check the encoding in your server-side script.

Posted by: bsn at September 20, 2006 10:56 AM .

Tonio said

Hi,
I've got a question, i would like to have a drop down menu, and make changing the values of aucosuggest with values taken from a db, the select must change with the value of the drop down menu.
To catch data from db, all ok, the only problem is to catch the value of drop down menu ... (i want that when i',m writing, for example, ita (he should write italia), before he checked that on drop down menu there's value, for example, Europe.

Any idea?
Thanx a lot

Posted by: Tonio at October 3, 2006 02:50 PM .

Brian M. Lima said

This is great work! I had it up and running in a few minutes and was able to add features a few minutes after that, and my JavaScript is still a little rusty.

I would like to propose this code be upgraded to an open source project. More in the immediate I would like to contribute my modifications. They are all just minor modifications that make the drop down menu behave more like common autocomplete fields users are used to in other programs.

1.) I added the ability to use the enter key to select a value from the dropdown list, as long as you do not use a formal submit button in your script the form will not auto submit. Basically this requires the form to submit using a regular button that calls the forms submit method onkeyup with ENTER and onclick.

2.) I cleaned up the behavior of the dropdown menu appearance and disappearance to make it feel a little more intuitive. As an example if a user were to tab out of a text field when the dropdown menu was displayed the menu would stay displayed until the timeout was reached. Also the menu used to appear when a user typed an exact match for something in the drop box. Basically when I implemented the enter key for selection, a user would select, the menu would disappear then reapear with only a single entry containing exactly what is in the text field as a suggestion.

3.) I fixed a few minor bugs that caused the system to try and search for nothing or less characters than the set minimum if a user deleted characters from the field.

4.) I cleaned up some of the code, not that it was messy at all but for newbies and such I added brackets around if statements to make the code a little more readable for newcomers.

Admittedly these are minor fixes but that make the user feel like the system is more intuitive, and behave in a manor more consistant with most users experience with other autocomplete fields in popular software.

The modifications I made have only been tested on FireFox and Opera. I run CENTOS and SUSE systems so it is hard for me to test other platforms.

Anyway, I would like to setup some way to share my contributions to this great piece of code. I am going to use it in a heavy load situation so I should be able to find and fix case issues as they come up.

Lastly I would like to thank Tim for writing and releasing this code. I figured it would take me a few days to write a bug ridden version with the same functionality. This definitely saved me allot of time and money.

Posted by: Brian M. Lima at October 8, 2006 07:12 PM .

Tim W said

Excellent but I'm not sure if I'm missing something... I would like to be able to use the keyboard to select from the list. i.e When I start typing in the text-box the list drops down with possibilities then using the down arrow I go down to the item I want to use then by pressing enter/return I would like to do a form post with the value from the drop down list not the text that I've typed in so far to the text box.

Posted by: Tim W at October 12, 2006 05:20 PM .

bsn said

Hi Brain/Tim

Don't have much time at the moment due to having real work to do (being the kind that keeps my family fed).

The reason why I didn't use either TAB or ENTER to select entries from the list is that Safari (a browser used by a large percentage of my visitors, and myself) always submits the form on ENTER, and moves focus on TAB. I initially wanted to use ENTER, but didn't want to produce a script that requires a javascript submit.

It is however true that being able to use the arrow keys to navigate up and down makes little sense if you can't use the keyboard to select. Left-over functionality. Maybe it would be a good idea to pass a parameter switching keyboard access on or off...

@Brian: If you've fixed a bug, send me the code and I'll see if I can update the code in the next couple of days. As for open-source; you're more than welcome to develop the script further - I have no experience in managing open source projects.

Posted by: bsn at October 12, 2006 05:29 PM .

Tim W said

Thanks for the quick response. I know your very busy, In the mean time is there any chance that Brian could let me know how he got round the issues. Thanks again Tim

Posted by: Tim W at October 12, 2006 05:52 PM .

Craig said

I seem to get an error when using my own XML data (generated from PHP). I have minchars set to 2 but when I type "Cl" the autocomplete list shows the complete list or items. Once I type "Cle" the list correctly only displays 2 items.

The data I am using is:


Attack of the Killer Tomatos
Chasing Amy
Clerks
Clerks 2
Star Wars

Likewise if I change minchars to 1, no matter what letter I put in the text box first I see the ENTIRE list, the reduced list only kicks in after typing a second letter.

This does not occur on your demo. Any suggestions?

Posted by: Craig at October 16, 2006 10:24 AM .

BSN said

@Craig:

can't say much from here: send me you php/mysql query, and I'll have a look at it. desk _at_ brandspankingnew _dot_ de

Posted by: BSN at October 16, 2006 05:44 PM .

Anand said

I am trying to make this work with ASP.NET, but it seems to give error. Could you let me know if it is possible to supply data to the script using an ASPX page?

Posted by: Anand at October 16, 2006 10:27 PM .

bsn said

@Anand:

I'm sorry, but I have absolutely no experience with ASP.NET. Can't help you there.

Tim.

Posted by: bsn at October 17, 2006 07:31 AM .

Nikola said

Hello,

Nice work.
However I was not able to use this with mysql records :(.
I do not know why? Any example ?

Thanks

Posted by: Nikola at October 19, 2006 07:16 PM .

Lee said

Hi, I love your script; however I don't know enough javascript to go through your code and solve my problem.

I can't add another onkeyup event. I tried this

new AutoSuggest(inputEl.id, options2);
inputEl.onkeyup+='alert("hi");';

but it jams everything.

My underlying problem is that I want to take the xml and further parse the entry when it is selected. The xml looks something like this:
<results>
<rs>name:::username</rs>
<rs>John Doe:::John15</rs>
</results>

Thanks for any help! You seem to be very helpful to everyone.

Posted by: Lee at October 22, 2006 06:08 PM .

Lee said

Hmmmm if there is actually a good way to use this xml for my code, I'd like to hear it too :)
If I got to use this xml format, I would want to put the name in one input field and the username in another.

<results>
<rs>
<username>John15</username>
<name>John Doe</username>
</rs>
</results>

Posted by: Lee at October 23, 2006 06:56 PM .

Lee said

Hi, has anyone else added an extra "onkeyup" attribute and can tell me about it?

Posted by: Lee at October 31, 2006 04:03 PM .

bsn said

Been away, been busy.

@Nikola:

Hmm. Not giving me much to work on. Check the XML that PHP is producing from your records...

@Lee:

new AutoSuggest(inputEl.id, options2);
inputEl.onkeyup+='alert("hi");';

You can't use the assignment operator to add extra code to a function! Nice try though :)
The script uses onkeydown instead of onkeyup. If the id of your field is 'inputEl', try using the following code.

document.getElementById('inputEl').onkeyup = function () { alert('hi'); }

Should work.


As for the XML problem: there's no quick-fix. You'll have to change/add quite a lot of code.


Tim.

Posted by: bsn at November 1, 2006 07:17 AM .

Lee said

It looks like the code uses both onkeyup and onkeydown on these lines:

this.fld.onkeyup = function () ...
this.fld.onkeydown = function(ev){ ...

Is there no way to retain both of these functions and add onto them with my own? I guess you're saying I'd have to go into your code and change/add the functions.

Posted by: Lee at November 1, 2006 03:48 PM .

bsn said

@Lee

Sorry. You're right. Quickest way would be to change the code to suit your purpose.

Tim.

Posted by: bsn at November 1, 2006 03:59 PM .

Terry Remsik said

I am interested in what Brian M. Lima was working on...

also.. what about making the entry limited to the whats in teh array (er drop down contents) ???

Thsk much

Posted by: Terry Remsik at November 2, 2006 01:37 PM .

Me said

Awesome, took me 5 minutes to get it up and running with XML - thanks. I hacked it to work with JSON data, as it would seem that that would be faster on the client side, particularly if you are returning many rows of data rather than a TOP 10* resultset. I can post the JSON changes if anyone is interested.

Posted by: Me at November 5, 2006 07:11 PM .

Alex said

Has anybody made it so that when the country is clicked on the menu disappears? I cant seem to figure out how to hack it.

Posted by: Alex at November 8, 2006 04:26 AM .

bsn said

@Me

I would be interested!


@Alex,

in the last function, setValue, replace

resetTimeout();

with

this.killTimeout();
this.clearSuggestions();

There is a usability reason behind the delay in closing the list when a value is selected: if the user clicks the wrong entry, he/she has half a second to correct the input. Without the delay, it's difficult to get the pulldown back again.

Cheers,

Tim

Posted by: bsn at November 8, 2006 08:03 AM .

Me said

Here is sample JSON data structure instead of XML (note: I changed the field names to Firms and Name from Results and rs, here and in the code)

{"Firms":[
{"Name":"Company Name One"},
{"Name":"Company Name Two"},
{"Name":"Company Name Three"},
]
}

Now you need to modify bsn.AutoSuggest.js in two places

setSuggestions() changes completely to:

_bsn.AutoSuggest.prototype.setSuggestions = function (req)
{
var jsondata = eval('(' + req.responseText + ')');
this.idAs = "as_"+this.fld.id;
this.createList(jsondata);
}

And then just change the beginning part of createList() to:

_bsn.AutoSuggest.prototype.createList = function(jsondata)
{
// clear previous list
//
this.clearSuggestions();

// create and populate ul
//
var ul = _bsn.DOM.createElement("ul", {id:this.idAs, className:this.oP.className});

var pointer = this;
for (var i=0;i {
var a = _bsn.DOM.createElement("a", { href:"#" }, jsondata.Firms[i].Name);

a.onclick = function () { pointer.setValue( this.childNodes[0].nodeValue ); return false; }
var li = _bsn.DOM.createElement( "li", {}, a );
ul.appendChild( li );
}

... rest of routine unchanged

I haven't tested this implementation vs XML, but I have tried similar conversions and timed them and the results were dramatic. The browser can convert the raw data into the list elemements much faster since it parses JSON data directly into a native javascript associative array, instead of having to drudge through parsing all the xml.

Posted by: Me at November 8, 2006 05:34 PM .

Rob C said

This is a great idea. One change I'd like to see is for it to put the completed text in the field as the user moves the mouse/uses the keys to highlight an entry. See the customize google firefox example that does this to auto-suggest searches. It would make it much more user-friendly and intuitive.

Great work though
Rob

Posted by: Rob C at November 13, 2006 10:59 AM .

Dominique said

Thx a lot for this wonderful script. I've notice mayba a bug.
I can Search a Country "Swi" for Switzerland, I can navigatate withe the arrows on my keyboard, but I can't validate my choice when I hit Enter... Empty... Is that a bug? Test on IE6 and Firefox 2 on XP.

Regards, Dominique

Posted by: Dominique at November 13, 2006 01:42 PM .

bsn said

@Rob C

Good idea...

@ Dominique

I've answered that before: ENTER submits the form on Safari (my primary browser). I initially had that functionality, but removed it until I find a workaround.

Posted by: bsn at November 13, 2006 02:55 PM .

Roland said

Hi, great script

One issue I have experienced is that if I modify a field (on some other page)that is used in the autocomplete, and then go back to the search I see the old results. I've made the cache option false but the results are the same. As an experiment I've manually flushed the browser cache and then things work.

Posted by: Roland at November 13, 2006 03:04 PM .

bsn said

@Roland

try adding the following headers to the php script to prevent caching:

header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header ("Pragma: no-cache"); // HTTP/1.0

Posted by: bsn at November 13, 2006 03:25 PM .

MichaelK said

I was also interested in passing a second bit of data in the form of an ID number. Your reasoning makes sense but what if the database depends on the IDs? For example there could be several different "Smith, John"s and each would have different IDs. This is my problem. The name is not necessarily unique in my system. After the user picked one they'd know if it was correct by the other information that autofilled.

Well, I have already created my own auto-suggest from scratch that works well returning the name and ID from the DB as a table :) so I suppose I'll just try to use your styling to get the nice drop down menu thing.

Thanks for sharing this nice autosuggest here anyway.

>>>
bsn said

@Jamie:

It is of course possible to pass more information in the response to the request.

However, an autosuggest field is meant to be an unobtrusive enhancement to the user experience: the form should still be usable without the javascript. If your form processing script is expecting a numeric id that is linked to a particular country, a user without javascript has no means of knowing that number, and you script won't know what to do with the input.

Let the form pass the field value as a string, and try and map it to an ID server-side.

Posted by: MichaelK at November 13, 2006 04:53 PM .

Roland said

BSN, its not possible to use the header function as once sent you can't resend i.e. you will get a "Headers already sent" error message

Posted by: Roland at November 13, 2006 06:47 PM .

bsn said

Hi Roland,

I'm using the header() function in the test.php script. You can use it as long as it comes before any other output (echo or print).

header ("Content-Type: text/xml");
header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header ("Pragma: no-cache"); // HTTP/1.0

echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>

Each time javascript makes an request for an xml document the server delivers a new document, with new headers. Seems to work for me, anyway.

Tim.

Posted by: bsn at November 13, 2006 06:57 PM .

Roland said

Cheers Tim, I think this would be a useful addition to the codebase, especially for people linking the autosuggest to dynamic databases

Roland

Posted by: Roland at November 14, 2006 10:28 AM .

Me said

It's easy to have a click submit an ID. You just have to get the ID value and create an HREF for it, rather than use the # placeholder. Here's an example (see my JSON post above to understand the data structure) where I see which of 2 inputs I am using. Then, either it is a list of firm names, or it is a collection of images which I am displaying in the pulldown, depending on a LIKE '%%' keyword search through a captions field in a database. So, depending on which search you are running, you get the following code. For firms, it just fills in the form field, for images, the click sends you to the new HREF.

var pointer = this;
for (var i=0;i {

switch(this.oP.script) // what data are we displaying?
{
case 'jsonfirms.aspx?':
var a = _bsn.DOM.createElement("a", { href:"#" }, jsondata.Firms[i].Name);
a.onclick = function () { pointer.setValue( this.childNodes[0].nodeValue ); return false; }
break;
case 'jsonimages.aspx?':
var imgSRC = '
'
var imgHREF = 'firm.aspx?id=' + jsondata.Firms[i].FirmID
var a = _bsn.DOM.createElement("a", { href: imgHREF }, imgSRC + jsondata.Firms[i].Caption );
break;
}

var li = _bsn.DOM.createElement( "li", {}, a );
ul.appendChild( li );
}

Posted by: Me at November 16, 2006 02:40 AM .

vickie said

Hi Bsn,

Found this code to be very useful, thanks for that. I have an issue on listing:
I have the autosuggest box just above an drop down(select) box. Hence whenever i type an input the list appears a layer behind the drop down box therefore hiding the values displayed in that space. this happens in IE6 but list appears in mozilla. Is there any workaround for that. Any inputs would be great.

Posted by: vickie at November 17, 2006 05:45 AM .

utsav said

thks man ur javascript files cleared a lot of concepts,that i faced problem in.quite interesting the concepts were that u used in javascripts.i was finally able to use it to build a script that uses sql server to retirive data in that "ul" list from which it can be then select by use of keyborad keys.

Posted by: utsav at November 17, 2006 06:13 AM .

Lapinbleu said

This script is really great... but it seems not to be XHTML Strict or Transitional compatible.
If you use this script, the ul.style['height'] will still be in read-only mode.
That's the same problem Jeffrey has.
It'll be wonderful that if the script were XHTML Strict compatible.

Posted by: Lapinbleu at November 17, 2006 01:23 PM .

Lapinbleu said

I found why the script wasn't XHTML compatible.

Those lines


if (ul.offsetHeight > this.oP.maxHeight && this.oP.maxHeight != 0)
{
ul.style['height'] = this.oP.maxHeight;
}


should be replaced by

if (ul.offsetHeight > this.oP.maxHeight && this.oP.maxHeight != 0)
{
ul.style['height'] = this.oP.maxHeight + 'px';
}


Just as simple as it seems! ;)

Posted by: Lapinbleu at November 17, 2006 01:52 PM .

bsn said

@Bluerabbit

Thanks for the tip! Code is updated.

Posted by: bsn at November 17, 2006 02:12 PM .

Steve P. said

Hi BSN

This is great work - I found however that adding the clearsuggestions (marked with an * below):

_bsn.AutoSuggest.prototype.setValue = function (val)
{
this.fld.value = val;
this.resetTimeout();
*this.clearSuggestions();
}

helped me out, as for some reason it wasn't firing within the setHighlightedValue function (IE 6.029 & FF 1.5.08). This means after selecting a value in the list it does not wait for a timeout anymore, but disappears immediately.

Have you (or anyone else) used this with IE7? (..grimace..)

Anyway - it's great to see a really good piece of code well written and explained BSN. If I could buy you a beer, I would. Cheers.

Posted by: Steve P. at November 21, 2006 03:58 PM .

atif said

Hi

Thank you really you are great to provide this, but I have a question. Can you please put the database extraction code to extract the users from username table and the field name is user.

how do we do that and put it in the array?

please guide.

thanks

Posted by: atif at November 22, 2006 10:18 PM .

shweta said

hi,
Thankyou for providing this autosuggestion box.i m very new with AJAX and XML.i used this code but i don't find any result.there is no error also.i think,i m lacking on this code
var options = {
script: "pathToScript.php?",
varname: "variableName"
};
var as = new AutoSuggest('idOfTextfield', options);

Here is my code:







function autos()
{
var options = {
script: "test2.php?",
varname: "auto"
};
var as = new AutoSuggest('auto', options);
}


ul.autosuggest
{
list-style: none;
padding: 0;
margin: 0;
[etc.]
}

ul.autosuggest li.highlight
{
[markup for highlighted list items]
}




Country:   



Please give your comments.
thankyou.

Posted by: shweta at November 23, 2006 08:34 AM .

Jerome Bourguignon said

Hello,

I made a small mod so that it will work on surnames too:

$tbl=split(",",$aUsers[$i]);
$name=$tbl[0];
$surname=$tbl[1];

if (strtolower(substr(utf8_decode($name),0,$len)) == $input || strtolower(substr(utf8_decode($surname),1,$len)) == $input)

I also changed the code so that you could put several names one after the other like in outlook, separated by ";".

$tbl=split(";",$input);
$input=trim($tbl[sizeof($tbl)-1]);

Posted by: Jerome Bourguignon at November 23, 2006 12:49 PM .

Hmmp said

Thanks for great script! I really love it and I'm using this in my content management system. :-)

- I disabled up and down keys, cause enter-key submits form in many browsers
- I added pointer.clearSuggestions() in line 181 (a.onclick = function () ...), cause more intuitive user experience - especially with long timeout.
- I made some changes in CSS (of course). Firefox sometimes have a "pixel-bug" with em-unit in line-height. Because that it's better to define background-color and side borders for whole UL-element.

Keep up the good work!

Posted by: Hmmp at November 27, 2006 02:08 AM .

Yahoo said

Script is great, one question though,
is it possible to pass a hidden value while displaying text in form field, like SELECT field does?

TEXT field would display: CountryXY
passed value would be: 123

Posted by: Yahoo at November 27, 2006 10:24 PM .

Yahoo said

Script is great, one question though,
is it possible to pass a hidden value while displaying text in form field, like SELECT field does?

TEXT field would display: CountryXY
passed value would be: 123

Posted by: Yahoo at November 27, 2006 10:26 PM .

myName said

hello!

nice script, i have some problems with more data and fast typing the suggest list is not actual.........

so long

Posted by: myName at November 29, 2006 01:27 PM .

Tez Read said

This is promising but im having trouble getting it to work. How can I have it so instead of the list being hard coded it pulls a list from a table called 'jargon'?

Posted by: Tez Read at November 29, 2006 06:00 PM .

Tez Read said

btw im talking about a mysql database table!

Posted by: Tez Read at November 29, 2006 06:01 PM .

bsn said

Hi Tez,

this is really just about the JavaScript part. It's beyond the scope of this article to explain the PHP / MySQL required to get an XML file containing a list out of a database. I've never written anything about server-side scripting on this site, and probably never will... There must be loads of PHP/MySQL 101s out there.

Cheers,

Tim.

Posted by: bsn at November 29, 2006 06:06 PM .

myName said

can everyone explain that, when i'm typing 3 chars and in the next step i'm deleting this 3 chars very fast the suggestions appears but no char is in the input field....

Posted by: myName at November 30, 2006 10:48 PM .

Comment test said

Greate work. Do you will like to i put it on download.com ???

Posted by: Comment test at December 1, 2006 05:45 PM .

Tiago Mendo said

Rolan there's a problem with the cache option:

if (!this.oP.cache) this.oP.cache = true;

no mather what you've put in cache option it always get true. Fixe this line to:

if (!this.oP.cache && this.oP.cache != false) this.oP.cache = true;

Tiago Mendo

Roland said

One issue I have experienced is that if I modify a field (on some other page)that is used in the autocomplete, and then go back to the search I see the old results. I've made the cache option false but the results are the same. As an experiment I've manually flushed the browser cache and then things work.


Posted by: Tiago Mendo at December 5, 2006 12:55 AM .

Josh said

I figured out how to make the autosuggest show on when focused and clear when the field loses focus.

replace line 24:

this.toID = setTimeout(function () { pointer.clearSuggestions() }, this.oP.timeout);

with

this.fld.addEventListener('blur',function () { pointer.clearSuggestions() },false);

this will make the suggestion box always visible when the field has focus and never visible when it doesnt. HOWEVER this won't work in IE because you must use attachEvent so put this code into the top of the bsn.AutoSuggest.js file


function createIEaddEventListeners()
{
if (document.addEventListener || !document.attachEvent)
return;

function ieAddEventListener(eventName, handler, capture)
{
if (this.attachEvent)
this.attachEvent('on' + eventName, handler);
}

function attachToAll()
{
var i, l = document.all.length;

for (i = 0; i if (document.all[i].attachEvent)
document.all[i].addEventListener = ieAddEventListener;
}

var originalCreateElement = document.createElement;

document.createElement = function(tagName)
{
var element = originalCreateElement(tagName);

if (element.attachEvent)
element.addEventListener = ieAddEventListener;

return element;
}

window.addEventListener = ieAddEventListener;
document.addEventListener = ieAddEventListener;

var body = document.body;

if (body)
{
if (body.onload)
{
var originalBodyOnload = body.onload;

body.onload = function()
{
attachToAll();
originalBodyOnload();
};
}
else
body.onload = attachToAll;
}
else
window.addEventListener('load', attachToAll);
}

createIEaddEventListeners();


Enjoy

Posted by: Josh at December 7, 2006 06:50 AM .

Josh said

in order for the dropdown to be clickable you must change the code above from:

this.fld.addEventListener('blur',function () { pointer.clearSuggestions() },false);

to

this.fld.addEventListener('blur',function () { setTimeout(function () { pointer.clearSuggestions() }, 300) },false);

Posted by: Josh at December 7, 2006 07:22 AM .

bsn said

Hi Josh,

why not just use the onfocus and onblur event handlers?

Cheers,

Tim.

Posted by: bsn at December 7, 2006 04:41 PM .

Josh said

I tried that, I can't seem to get it to respond right.

Posted by: Josh at December 7, 2006 09:24 PM .

peter said

Hi, is it possible to submit the form after clicking on some of the results? It would save the user one click...

Posted by: peter at December 19, 2006 06:49 PM .

kk said

Jeffrey Ropp said

Nicely done. For some reason, my results dont appear within a scroll area? I copied most of your CSS and still can't get it to work.

I've also found that my results aren't always qualified by the first character provided. You are welcome to test with my sample data: http://www.zoyzoy.com/cellphoneservicereport/phones.php

Try an "S" first.

Any thoughts would be appreciated!

Thanks,
Jeff

Jeffrey Ropp said

Nicely done. For some reason, my results dont appear within a scroll area? I copied most of your CSS and still can't get it to work.

I've also found that my results aren't always qualified by the first character provided. You are welcome to test with my sample data: http://www.zoyzoy.com/cellphoneservicereport/phones.php

Try an "S" first.

Any thoughts would be appreciated!

Thanks,
Jeff

Jeffrey Ropp said

Nicely done. For some reason, my results dont appear within a scroll area? I copied most of your CSS and still can't get it to work.

I've also found that my results aren't always qualified by the first character provided. You are welcome to test with my sample data: http://www.zoyzoy.com/cellphoneservicereport/phones.php

Try an "S" first.

Any thoughts would be appreciated!

Thanks,
Jeff

Robert said

Very interesting.
I still have a question.
Can i use this example for a site that needs more than 1 autosuggest field on the same page ?
I have several fields that need auto-completion.
Thanks for a response

peter said

Hi, is it possible to submit the form after clicking on some of the results? It would save the user one click...

peter said

Hi, is it possible to submit the form after clicking on some of the results? It would save the user one click...

Josh said

I tried that, I can't seem to get it to respond right.

Josh said

in order for the dropdown to be clickable you must change the code above from:

this.fld.addEventListener('blur',function () { pointer.clearSuggestions() },false);

to

this.fld.addEventListener('blur',function () { setTimeout(function () { pointer.clearSuggestions() }, 300) },false);

Josh said

I figured out how to make the autosuggest show on when focused and clear when the field loses focus.

replace line 24:

this.toID = setTimeout(function () { pointer.clearSuggestions() }, this.oP.timeout);

with

this.fld.addEventListener('blur',function () { pointer.clearSuggestions() },false);

this will make the suggestion box always visible when the field has focus and never visible when it doesnt. HOWEVER this won't work in IE because you must use attachEvent so put this code into the top of the bsn.AutoSuggest.js file


function createIEaddEventListeners()
{
if (document.addEventListener || !document.attachEvent)
return;

function ieAddEventListener(eventName, handler, capture)
{
if (this.attachEvent)
this.attachEvent('on' + eventName, handler);
}

function attachToAll()
{
var i, l = document.all.length;

for (i = 0; i if (document.all[i].attachEvent)
document.all[i].addEventListener = ieAddEventListener;
}

var originalCreateElement = document.createElement;

document.createElement = function(tagName)
{
var element = originalCreateElement(tagName);

if (element.attachEvent)
element.addEventListener = ieAddEventListener;

return element;
}

window.addEventListener = ieAddEventListener;
document.addEventListener = ieAddEventListener;

var body = document.body;

if (body)
{
if (body.onload)
{
var originalBodyOnload = body.onload;

body.onload = function()
{
attachToAll();
originalBodyOnload();
};
}
else
body.onload = attachToAll;
}
else
window.addEventListener('load', attachToAll);
}

createIEaddEventListeners();


Enjoy

Posted by: kk at December 26, 2006 06:06 AM .

kk said

peter said

Hi, is it possible to submit the form after clicking on some of the results? It would save the user one click...

Josh said

I tried that, I can't seem to get it to respond right.

bsn said

Hi Josh,

why not just use the onfocus and onblur event handlers?

Cheers,

Tim.

Josh said

in order for the dropdown to be clickable you must change the code above from:

this.fld.addEventListener('blur',function () { pointer.clearSuggestions() },false);

to

this.fld.addEventListener('blur',function () { setTimeout(function () { pointer.clearSuggestions() }, 300) },false);

Posted by: kk at December 26, 2006 06:07 AM .

TEW said

Nice usable code!

I have found that when usage of ÅÄÖåäö in the php array
(eg. $aUsers = array(
"Ädams, Egbert",
"ädans, Villiam",
"Altman, Alisha",
"archibald, Janna",
....)

If you type ä, then the second item will be suggested
and if type Ä, the first item is suggested.
If you type a or A both the third and fourth items will be suggested in both case.

Have you suggestion to solve this?

TEW

Posted by: TEW at December 28, 2006 12:37 AM .

VJ_123 said

Hello,

I like this autosuggest. Can anybody help to solve this I am trying to use in asp pages.
I replace the php script to asp, It gives the Ajax Error:500 what it means and how can resolve it. or let me know how can debug this error!
Thanks in advance.

Posted by: VJ_123 at December 28, 2006 07:58 PM .

peter said

The solution to question "is it possible to submit the form after clicking on some of the results? It would save the user one click... is finally easy:

in bsn.AutoSuggest.js on line 61 add:
if (!this.oP.whereSubmit) this.oP.whereSubmit = null;

about line 187, where there is a.onclick=function() ... add in the body of the function just before "return false":
var formName = (pointer.oP.whereSubmit);
if (formName != null) {
var form = document.getElementById(formName);
form.submit();
}

and in your html doc, suggesting it's jamietest.html, add to your form html element attribute "id='searchForm'", and to the input element add any custom value to attribute "name" (isn't defined yet)
Secondly, in the javascript section, my "options1" array looks like this:
var options1 = {
script:"test.php?",
varname:"input",
minchars:1,
whereSubmit:"searchForm"
};

and that's all and it's working now. You can now just click on one of the offered results and the form is submitted with it

Posted by: peter at December 30, 2006 01:41 PM .

Suran said

This is really neat. Thanx a bunch!

This works pretty well in most places, but on some pages of mine that have some other JS stuff happening, it throws an error. On FireFox & IE 6.
It occurs when a letter is entered in to the text field afresh.
FireBug on FireFox says _bsn.Ajax is not a constructor..
Any ideas?

Posted by: Suran at January 4, 2007 03:30 PM .

Fredrik said

I take the suggestions from mysql database but when typing I only
get suggestions for every other typed char. like the 3,5,7th char i type. I have the select stuff etc in the "test2" file, should one make the database query somewhere else? If I replace the query with a fixed array then it works like it should... I also have made the changes some other people have, like enabling the enter button and adding action when you mouseclick. Anyone else had problems with the suggestion field coming and going?

Posted by: Fredrik at January 7, 2007 09:26 PM .

Amanda said

Hi All,
I want to have a text box which will act like a true combo box and show a list of valid values from the databse that shrinks as the user types. So, if the user types "UNI" in the text field, they would see a list like:
United States Of America
United Arab Emirates
Uganda
Ukraine

I found the Autosuggest example very usefule and tried to follow the steps menioned. But I get errors when i follow the steps provided in this link.
First error is that when i put the following code
var options = {
script: "pathToScript.php?",
varname: "variableName"
};
var as = new AutoSuggest('idOfTextfield', options);

in a javascript function and call this function at the onChange and onBlur event of my input text box I get the error message that it is unable to find the JavaSCript function.
The second problem is that instead of pathToScript.php I want to write a Java file. How can i do that?

Any help would be very much appreciated. Thanks in advance.
-amanda

Posted by: Amanda at January 8, 2007 09:47 PM .

Leon said

Hi, this is a very easy to use script and I appreciate the work you've done. I wonder, if there is a way to shorten the time between clicking a result and the result sheet disappearing?

Posted by: Leon at January 10, 2007 06:17 PM .

GnunuX said

What about license ?

I would like to use your script in a GPL project. But you don't have put any license to your code. Could you please tell me in which license is this script ?

Posted by: GnunuX at January 10, 2007 08:49 PM .

Amanda said

Jeffrey Ropp said

Nicely done. For some reason, my results dont appear within a scroll area? I copied most of your CSS and still can't get it to work.


I've also found that my results aren't always qualified by the first character provided. You are welcome to test with my sample data: http://www.zoyzoy.com/cellphoneservicereport/phones.php


Try an "S" first.


Any thoughts would be appreciated!


Thanks,
Jeff

Posted by: Amanda at January 11, 2007 11:33 PM .

bsn said

@Leon:

Change the last function:

_bsn.AutoSuggest.prototype.setValue = function (val)
{
this.fld.value = val;
this.resetTimeout();
}

to

_bsn.AutoSuggest.prototype.setValue = function (val)
{
this.killTimeout();
this.clearSuggestions();
}

This will remove the list immediately when an option is clicked.


@GnunuX:

I've got a creative commons license at the bottom of the page, if that helps. Basically, the script is yours to do with as you want...


@Amanda:

I'm not exactly sure what you are trying to achieve by calling the constructor function in the onChange handler of a text input. Call the constructor function once when the page loads; it will add an onKeyUp function to the text input passed to it, which then triggers the autosuggestion.

Tim

Posted by: bsn at January 12, 2007 09:46 AM .

Jonathan said

Is it possible to have the number of results appear on the right hand side of the suggestions

result1 200
result2 120
result3 30

etc?

Great work and thanks in advance!

Posted by: Jonathan at January 14, 2007 12:56 PM .

Thomas Kulvik said

Hi. Thanks for this wonderful script!

I would really like to be able to use the Enter key for choosing a result and submitting it, but that won't work because of the enter = submit problem with some browsers. The next best thing would be to give the text-field focus right after choosing something with a mouseclick. That way, the user can just click the the mouse and then hit the enter key to submit the form.

Have anyone managed to do this?

-Thomas

Posted by: Thomas Kulvik at January 14, 2007 08:30 PM .

James Logsdon said

For those of you wishing to renable the ENTER key, it's quite simple.

createList() has the switch block for the key presses, on line 235 I added:

			case RETURN:
			pointer.setValue(_bsn.DOM.getElement(pointer.idAs).childNodes[pointer.iHighlighted-1].childNodes[0].childNodes[0].nodeValue);
			return false;
			break;

Remember that this doesn't work right in Safari.

Posted by: James Logsdon at January 15, 2007 01:46 AM .

Hiral said

Hi,

I must say that your code is simply amazing and it didn't take me long to set it up using a simple classic ASP script and get auto suggestion values from the database.

Actually, what I am after is a way to assign an ID of the selected suggestion to a hidden field on the form so that it could be used to do some server side processes on submission of the form and at the same time a bit of AJAX that populates some related fields on the same form depending on that ID so that user is sure that he has selected the right record.

I want to

1) Keep the ID of the record hidden from user [Firstname, Lastname, ID (but not visible to user)] in the suggestion dropdown and extract the hidden ID from the list when suggestion is clicked.

2) Customise the onclick event and assign a custom function so that I could do some other smarts on the same form when the record is selected.

I hope I am able to explain my problem. I would be really grateful if someone could help me out with this.

Thanks.

Posted by: Hiral at January 18, 2007 12:46 AM .

Posted by: wowgold at January 25, 2007 12:37 PM .

zajicek said

Woa :) just what i was looking for. Thanks! :)

Posted by: zajicek at January 25, 2007 05:31 PM .

vishal said

thanks a lot.. i am newbie and i can learn from all this..

Posted by: vishal at January 28, 2007 06:05 AM .

atul said

Hi,
This is a nice script and I could start using it in no time.
However, I am facing problem with dropdown list background transparency. The results are populated fine in dropdown list but the list is not quite visible as the other form fields, cover the dropdown list. The list does not come in foreground and not quite readable..
I am using tables for layout. I tried changing to div layout, but the text fields still obstruct the dropdown list display.
I tried putting filter:alpha(opacity=100); in css, but it did not help.
Could you please suggest some way I can make the list opaque so that the other fields do not obstruct the view of the drop down list.

Regards,
Atul.

Posted by: atul at January 29, 2007 09:59 PM .

bsn said

Hi Atul,

because the dropdowns are added after the last element in the body, and positioned absolutely, they should be positioned above the rest of the content, especially if you are only using tables for layout. Have you got anything else with a z-index value on the page, that might be positioned above the dropdowns?

It's always hard to give an answer when you can't see the example (got a link?)

Cheers,

Tim.

Posted by: bsn at January 29, 2007 10:55 PM .

John West said

For those of you wanting to use ASP.NET with this code, simply change the test.php page to test.aspx and change the code to this:

Finally open up ajax_autosuggest_autocomplete.html and change the javascript at the bottom to


var options = {
script:"test.aspx?",
varname:"sInput",
minchars:1
};
var as = new AutoSuggest('testinput', options);

and that's it! happy programming!

Posted by: John West at January 29, 2007 11:12 PM .

John West said

For those of you wanting to use ASP.NET with this code, simply change the test.php page to test.aspx and change the code to this:

Dim aCountries As [String]() = { _
"Afghanistan", _
"Albania", _
"Algeria", _
   etc...
"Zambia", _
"Zimbabwe" _
}
	
Dim sInput As String = LCase(Request.Form("sInput"))
Dim nLen = sInput.Length
Dim aResults() As [String]
	
If (nLen) Then
 Dim i as integer, nIndex As Integer = 0
 For i = 0 To UBound(aCountries)
  If LCase(aCountries(i).SubString(0,nLen)) = sInput Then
   ReDim Preserve aResults(nIndex)
   aResults(nIndex) = aCountries(i)
   nIndex = nIndex + 1
   'If nIndex = 10 Then Exit For
  End If
 Next
	
 Response.ContentType = "text/xml"
 Response.Write("xml version='1.0' encoding='utf-8'")
 Response.Write("results")
 For i = 0 To UBound(aResults)
  Response.Write(" rs" & aResults(i) & "/rs")
 Next
 Response.Write("/results")
End If

****NOTE****
As you can tell, there are no brackets around the xml tag, the results tag, nor the rs tags. PUT THE BRACKETS AROUND THEM! I would have done so but each time i tried it wouldn't display.


Finally open up ajax_autosuggest_autocomplete.html and change the javascript at the bottom to

 var options = {
   script:"test.aspx?",
   varname:"sInput",
   minchars:1
 };
 var as = new AutoSuggest('testinput', options);
and that's it! happy programming!

Posted by: John West at January 29, 2007 11:21 PM .

John West said

One more thing, if you run into the AJAX Error 500 while using my code and using Mozilla, simply change the code in test.aspx from:

Dim sInput As String = LCase(Request.Form("sInput"))

to:

Dim sInput As String = LCase(Request("sInput"))

cheers :)

Posted by: John West at January 29, 2007 11:25 PM .

John West said

@BSN

I successfully tested the code (PHP and ASP.NET) on Mozilla FireFox 2.0 and IE 7.0.

Posted by: John West at January 30, 2007 11:06 PM .

bsn said

Hi John,

Thanks for your work, although I have never done anything in ASP.NET.
If you send me your test file, I'll include it in the download.

Tim.

Posted by: bsn at February 1, 2007 08:58 AM .

John West said

What is your email address?

Posted by: John West at February 1, 2007 11:30 PM .

Greg said

There is a display problem in IE where Form Elements such as comboboxes display over the autocompletion list. This seems like a css z-index setting, but I can't say for sure without isolating it in the source code.

Posted by: Greg at February 3, 2007 02:25 AM .

Leon said

Hi Timothy, I have changed to a new server and after uploading the files in the AS1.2 archive to my server it doesn't work anymore. I get "xml has no properties" error in FF Javascript Console. The error reported is

Hata: xml has no properties
Source file: http://www.mydomain.com/js/bsn.AutoSuggest.js
Line: 146

Posted by: Leon at February 6, 2007 10:01 AM .

Hiral said

Has anybody had a chance to look at my problem?

Thank you,
Hiral.

Posted by: Hiral at February 7, 2007 03:14 AM .

bsn said

Hi Hiral,

check out the new version (v.2)

Cheers,
Tim

Posted by: bsn at February 7, 2007 08:37 AM .

bsn said

Comments are now closed. Please go to this page.

Posted by: bsn at February 7, 2007 08:57 AM .