The Dangly Bits

Taking the IE out of danglie

The Dangly Bits header image 2

jquery.suggest, an alternative jQuery based autocomplete library

June 29th, 2007 by VulgarisOverIP

Update 2: After reading Peter-Paul Koch’s amazing book on Javascript, I’ve come to realize that the offset problem with the drop down in IE is probably caused by the use of em’s on padding/margins of autocomplete’s offsetParents.

Update 1: I realize the drop down is slightly off in IE 6&7, I think it has something to do with Wordpress or K2’s stylesheets. Also, I’m in the process of updating the script to work better when the window is resized. Keep checking back here for more updates.

Try it:


jquery.suggest is my attempt at a jQuery autocompleter that functions much like Google Suggest. I used code and techniques from two popular jQuery autocompleters:

Originally, I used the first library in all my code but found that it just didn’t have the flexibility I needed and it had not been maintained in a long time. The biggest missing feature is the ability to run a function upon selecting something from the drop down.

While the Interface autocompleter seems to be rather up to date, there’s still a lot of problems with it. It’s tied to the Interface 1 library (which looks dead), the <iframe> code with is supposed to help cover forms in IE doesn’t work over HTTPS and the caching system is so screwed up I ended up having to manually disabling it.

I also found that the two implementations acted differently in different browsers including IE 6&7, Firefox and Safari. Sometimes tab would select an item, sometimes it would move to the next <input> element. Sometimes typing in something (which I didn’t want to match) and hitting enter would submit the form as usual, sometimes it would force me to select the first match.

Anyways, enough complaining, here’s the feature list:

  • Smart cache system that takes a maximum cache size in bytes and uses MRU list to discard items. Oh, and the caching works correcly.
  • Doesn’t assume that you have to choose an item from the drop down list. If an item is selected and you hit enter or tab, that item is copied to the <input> element. Otherwise, hitting enter or tab works just like a normal <input> element.
  • Event handler for selecting a drop down item.
  • Works the same in Firefox, Safari, IE 6&7.

It’s really easy to use, here’s the code for the suggest box above:

jQuery(function() {
jQuery("#suggest").suggest("files/search.php",{
onSelect: function() {alert("You selected: " + this.value)}});
});

Here’s the stylesheet and the source for the PHP file (blatantly stolen from autocomplete) which returns the items. And finally, download the source to the suggest library here. You can find more information about possible options at the bottom of the source.

The only requirement is jQuery itself and the dimensions plugin, although the script will try to use the bgiframe plugin if possible (to fix IE 6).

Tags: 52 Comments

Leave a Comment

52 responses so far ↓

  • This is a great shot at making “the final autocompleter” for jQuery. It works well in all modern browsers. Were are you at with the next release? Have you considered contributing it to http://jquery.com/plugins ? I think it’s better than the ones listed there.

    Thanks, Mikael

  • [...] more information, please see this previous post. While the plugin works in Opera, it’s not perfect (which is why I didn’t mention it [...]

  • It would be nice if you provide too a full list of possible options. The option hash seems to have 5 to 7 options or so, but there is no documentation. :-/

  • I found your plugin very useful, thanks a lot for it!!!.
    As soon as I started using it I realized (as you said) that chaching works great.
    Nevertheless it would be great having the option to turn the cache off to deal with those cases when the lists that your pligin manage change during runtime.

    Regards,
    Fernando

  • I have two select boxes before i get to my auto complete input. The selects are for “Country” & “State”. I want the “City” input to be an auto complete. I want to filter out the cities which are not in a particular state.

    Here’s my code:
    $(”#city”).suggest(”search.php?country=” + $(”#country”).val() + “&state=” + $(”#state”).val(), {});

    This work, but only allows the initial values for state and country to get passed into the script. I’ve attempted this, but it doesn’t change anything and only the initial values continue to be passed.

    $(”#country, #state”).change(function() {
    $(”#city”).suggest(”search.php?country=” + $(”#country”).val() + “&state=” + $(”#state”).val(), {
    });
    });

    Any insight would be appreciated.

  • jquery@j0rd.com, that’s a tough one with the current code. I’m currently working on an updated version of the library and I’ll consider something to make this easy.

    My first instinct would be to add a new option (something like: getURLCallback) that would be called with the source as the input and the output used as the $.get URL. This would require very little modification to the library if you’re up for it.

    Otherwise, I’ll have an updated jquery.suggest script up soon.

  • resolved my issue. it was an order of operations issue

  • Thank you for a great addition to the jQuery library!

    I can not get the word list to display correctly in MSIE 6 I keep experiencing the zIndex issue that I am sure was meant to be fixed with the bgiframe extension. (Input elements shine through the list)

    Do I need to do anything to get this to work? (Besides including it)?

  • Also… Is there a way to make it required that the user selects one of the items in the list?

  • I have a problem with the results list not displaying on the right place on FF, on IE it displays below the box as it should but in FF it displays on the top left corner… any ideas?

  • What license are you releasing this under?

  • Anton, this is probably a problem with your CSS. Try stripping it away one piece at a time until you isolate what’s causing the problem and then either fix it or work around it.

    Peter, not sure exactly, haven’t had time to think about it recently. I’ll clarify this with the next release version (soon, I promise!!!), but in any case it’ll be something VERY liberal.

  • Is it possible to manage the dropdown list so that it (a) is aware of the window boundaries – i.e., switch from ‘below’ to ‘above’ the input box if it’s close to the bottom; (b) become a scrollable list that the developer can constrain to a given size – e.g. limit vertical size to a specific number of rows?

    I find that on some browsers, the list can fall below the visible area of the window, and attempting to scroll the window then closes the list because it loses focus.

  • hi,It some like does not support Chinese?So slow~~Could u change that?

  • Any plans to add a way to do a local autocomplete? By passing an array like in the autocomplete plugin?

  • Hi, your plugin is sweet. There’s an odd issue with inputs that involve the shift key in IE7. In the example on this page, try typing the following (clearing the textbox between each try.)

    ab
    aB (shift+B)
    AB (shift+A,shift+B)
    AB (shift+AB)

    Only the first and last combination will bring up the suggestions in work in IE7. It’s not recognizing the change if the last character is a shift+ character.

  • So I was just battling with the suggest css and ie with em margins and padding, I think I’ve come up with a much cleaner way to get the list in the correct location.

    Here are the changes I made to jquery.suggest.js:

    change:
    $results.addClass(options.resultsClass).appendTo(’body’);

    to:
    $results.addClass(options.resultsClass).insertAfter($(input));
    which puts the list right after the field with a suggest applied rather than at the bottom of the page.

    Then I’m pretty sure you could kill the reset position function, but I just commented out the top and left lines for now.

    function resetPosition() {
    // requires jquery.dimension plugin
    var offset = $input.offset();
    $results.css({
    //top: (offset.top input.offsetHeight) ‘px’,
    //left: offset.left ‘px’
    });
    }

    In the CSS then I needed to add top and left o ac_results (my guess here is that you’d need to adjust these depending on the size of the input box.
    .ac_results {
    left: 10em;
    top: 4.5em;
    }

    These changes appear to produce consistent results across Safari, FireFox, and IE 6 and 7.

  • Is there some way to auto submit the form after clicking or selecting an option from suggest?

  • After playing with my above changes I found that I needed to make too many changes to the page code to have the suggest box show up in the correct location for my liking so I adjusted this slightly. Here’s a diff off the current suggest 1.1. The major changes are that the javascript now wraps the input box in a div that is relatively placed and the results are attached directly after the search box instead of at the bottom of the page so that they appear in the correct place in the flow of things and can be absolutely positioned from the top of the input box instead of the top of the page. This allows for perfect placement on any page including pages with padding or margins in ems.

    26,30c26,28
    ‘);
    $results.addClass(options.resultsClass).appendTo(’body’);
    >
    >
    58a57,60
    > $results.css({
    > top: (offset.top input.offsetHeight) ‘px’,
    > left: offset.left ‘px’
    > });

    You’ll need to add something like:

    left: 0;
    top: 1.3em;

    to .ac_results {} in the css file.

  • Argh! there were problems with the diff on my last post. Here’s a human readable version:
    replace:

    $results.addClass(options.resultsClass).appendTo(’body’);

    with:

    // Create a relatively placed element that wraps the search box so positioning
    // can be relative to the search box
    $input.wrap(”);
    // Attach the search results to the search box
    $results.addClass(options.resultsClass).insertAfter($input);

    replace:
    function resetPosition() {
    // requires jquery.dimension plugin
    var offset = $input.offset();
    $results.css({
    top: (offset.top input.offsetHeight) ‘px’,
    left: offset.left ‘px’
    });
    }

    with:

    function resetPosition() {
    // requires jquery.dimension plugin
    var offset = $input.offset();
    }

  • can’t use the Chinese ……….

  • I added this so line 114 so I could use it properly when the input element was inside a floating div (a drag-able)

    [code]
    resetPosition(); // force the box to always appear under the proper location ( especially if the input element has moved ... like its in a drag-able )
    [/code]

    Thanks for the awesome jQuery plugin.

  • Maybe I’m wrong, but with your browser detection problem on line 46:
    I use this:
    $(input).keyup(function (e) {
    var keyCode = e.keyCode || window.event.keyCode;

    }
    And I think you can do it analog.

  • After writing a auto-suggest script and didn’t like the cosmetics, I searched for one and found your plugin.

    Nice, easy to use. But…… There is always a but! Right?

    I had to mis-something, but how do you limit the display box? Does it scroll? I hit “D” and then “E” and POOFF – all 200 “Demo UserXX” items display creating a huge Y height page with scroll bars. I don’t want that. :-)

    This is too obvious. I had to miss something here. Maybe there is an option?

    Also, Why not trigger off the first character? You can use OnKeyUp for this which will give the value for the input box. The others will not give you the value until the 2nd character is hit.

    Thanks

  • Hi, I was able to get the auto suggest/complete to work fine, but I did run into an issue which I can’t seem to find any reasonable answer for.

    I have two iframes, one above the other so they are stacked as horizontal bars. Inside of the top one is the text box I want to have the auto suggest on. so the layout is like so:

    +—————+
    | [input] |

  • Hey Guys,

    great plugin!

    Although I had the need to add an option which allows you to multiple select suggested items.
    That means that when you select a result item, its getting pasted in the target input with a defineable separator. After that you can type another phrase which is appended to the input value and on and on and on…

    here’s the code:

    1. extend the options:

    options.multiple = options.multiple || false;
    options.multipleSep = options.multipleSep || “, “;

    2. replace this function

    function selectCurrentResult() {

    $currentResult = getCurrentResult();

    if ($currentResult) {

    if(options.multiple) {
    if( $input.val().indexOf(options.multipleSep) != -1 ) {
    $currentVal = $input.val().substr( 0, ( $input.val().lastIndexOf(options.multipleSep) + options.multipleSep.length ) );
    } else {
    $currentVal = “”;
    }
    $input.val( $currentVal + $currentResult.text() + options.multipleSep);
    $input.focus();
    } else {
    $input.val($currentResult.text());
    }

    $results.hide();

    if (options.onSelect)
    options.onSelect.apply($input[0]);

    }

    };

    3. edit this function:

    function suggest() {

    var q = $.trim($input.val());

    if(options.multiple) {
    var multipleSepPos = q.lastIndexOf(options.multipleSep);
    if(multipleSepPos != -1) {
    q = q.substr(multipleSepPos + options.multipleSep.length);
    }
    }

    Eventually you shoud add this feature to the official release.

    Cheers
    Alex

  • I’m a little confused as to what I need to do with the PHP code when I’m fetching the data from a mysql DB. IE: say I’m fetching names. Do I simply echo the names or am I supposed to put the data into a particular format like an array, XML or JSON? Can I get an example?

    Thanks

    -Mike

  • After days of looking for a decent “simple” type ahead script I finally found jQuery and from there this suggest script – thank you! :)

    It seems very solid and well working.

    One thing though. I would love to see the option to have “Loading…” or whatever HTML tag for showing that results are in the process of showing.

    Also – reading the comments here, I think having the option for multiple input fields on the same page is great.

    Looking at Alexander’s patch it seems he made most the work. I didn’t try it yet, but it seems pretty straight forward. An example would have been the icing on the cake :)

  • And another thing. A small addition to the result set. If the second last result is empty, the last could contain a code for stating how many more result are waiting.

    My DB contains 23k items and I search inside all strings (%$q%) meaning a lot of matches.

    Right now I just add “…and X more results” as a dummy result, which is kinda half hearted – but it works :)

    Again – thank you for a very nice plugin.

  • Add this in the top of the main function:

    var loadingText = ” + ‘Loading…’ + ”;
    var loading = [];
    loading[loading.length] = loadingText;

    Then add the second line of these 3 in the “suggest” function:

    } else {
    displayItems(loading);
    $.get(options.source, {q: q}, function(txt) {

    And you have a simple “Loading…” text while the server is processing your request :)

  • I find a bug in your code,”$results.html(html).show();” remove the iframe html and make it not work

  • Hi guys,
    thanks for this greate plugin.
    I have one problem.
    How to pass multiple parameters with query.
    I need pass not only search query, i need also pass type(’cars’, ‘mobiles’, …) and some additional parameters.
    My code is following:
    jQuery(function() {
    jQuery(”#suggest”).suggest(”searchSuggest”,{source:”ltype”+$(’#ltype’).val()})
    });

    But it is don’t work.

    How can i fix it?
    Thank You,
    Yaroslav

  • Whenever I call a new .suggest() on a text box, the number of dropdown instances increases by one.

    Couldn’t figure out how to fix this one. Any suggestions?

  • I’ve come up with a simple hack that will allow you to use DWR calls as an alternative to the current regular AJAX calls, to do so, just replace this code:

    $.get(options.source, {q: q}, function(txt) {
    $results.hide();
    var items = parseTxt(txt, q);
    displayItems(items);
    addToCache(q, items, txt.length);
    });

    with:

    if(typeof options.source == “string”)
    {
    //This is what suggest would do by default…
    $.get(options.source, {q: q}, function(txt) {
    $results.hide();
    var items = parseTxt(txt, q);
    displayItems(items);
    addToCache(q, items, txt.length);
    });
    }
    else
    {
    //This is the DWR implementation hack… yeah, need to DRY some code here, but just want to keep it a simple hack!
    options.source(q, function(data)
    {
    var txt = “”;
    for(var i = 0; i < data.length; i++)
    {
    txt += data[i] + “\n”;
    }
    $results.hide();
    var items = parseTxt(txt, q);
    displayItems(items);
    addToCache(q, items, txt.length);
    });
    }

    This hack won’t break the current way of using it. To use DWR, just pass the source as the class.method like: MyDWRClass.myDWRMethod without quotes, then it will recognize it is a class and will send the first parameter as the typed text and handle the data that comes back.

    Maybe this can be patched to the main plugin? Thanks.

  • hi
    i haven’t actually tried your plugin (yet!) but i’m wondering if i can restrict the search only around the first letters i type in the input field. I mean:

    i type “a” and i receive only words starting with “a”, then i add “s” and i receive only words starting with “as”.

    thanks
    vitto

  • Learn to write documentation!!
    Danke.

  • Hi,

    Like jquery@j0rd.com above I have an auto complete that is dependent on another select box, I have tried adding an change function to the other select box which

    eg
    HTML

    one
    two

    JS
    var s = $(’#select’);
    s.change( function() {
    $(’#suggest’).suggest( ‘?page=suggest&select=” + s.val() );
    });
    s.change();

    This kind of works execpt that each time you choose a different value of #select you get a new suggest action which appears as well as the old suggest. Is there a way that you could delete old suggests if they exist?

    Also is there a way to get a key value pair like a select list may be adding the key to a hidden field?

    Ivan

  • [...] browser. Treetable Make a tree view out of an HTML table. Tree ViewEXCELLENT Tree view controls. Suggest Add autocomplete to input fields. YAV Form validation library. jqUploader Provides a status bar for [...]

  • I have your site for its useful and funny content and simple design..

  • How would you go about returning a second response as well as the name that could be inserted into a hidden field.

    like searching for “pet” would return “peter” into the text input field and “8″ into a hidden input field

  • [...] Suggest Add autocomplete to input fields. [...]

  • I had some problems getting the select boxes do display in IE6 on top of drop-downs, even though I had included the bgiframe script.

    I made the following changes, and it seems to be working:

    1) Call bgiframe after the adding items to the ul element, instead of where it was called before. So in the function “displayItems” there is a line “$results.html(html).show();” – directly beneath that I make the call to bgiframe:

    try {
    $results.bgiframe();
    } catch (e) { }

    2) The last line of the function “nextResult” makes use of the first child CSS, which I don’t hink works on IE6, so I replaced it with

    $results.children(’li’).eq(0).addClass(options.selectClass);

    Cheers,

    jmcd

  • for those of you trying to do a suggest based on another selects output just make sure you call bind the calling the suggest init every time the select changes for example:

    $(’#state’).bind(’change’, function() {
    $(”#suburb”).suggest(”someurl/”+$(’#state’).val(), {
    onSelect: function() {
    $.get(’someurl/’, {suburb:$(’#suburb’).val()}, function(data) {
    $(’#postcode’).val(data);
    });
    }
    });
    });

  • great extension!!!
    just a few suggestions:

    1. It seems you save the popup position when the page loads, this may be better placed in the showSuggestions functions. The problem that I am having is that other javascript controls change the height of the page and mess with the suggest box position.

    2. It would be great if there would be a way to add html into the results (perhaps as a settings). that way we could do cool things like add relevant images to our suggestions!

    3. It would also be very useful if there was a method of adding results other than a URL for AJAX. This way we can generate suggestions programatically.

    cheers
    Pete

  • Hi there!

    I have installed the script like you have in your example, but it will not work in IE6&7. In FF, Opera and Safari it is fine, but in IE there are no results shown. I get no error report in IE oO

    Some ideas?

  • Hi,

    It’s a good plugin…but I have one problem…I need to show the suggested string but I need to return the key of data base…

    Its possible?

  • The code is nice but i need a real time demo with atleast 5 different example. sothat i can choose one the best suitable for me. thanks

  • Well this doesn’t make sense. With the plugin if you enter a ‘\’ after a couple characters it would cause a Javascript error. But this does not happen on your example suggest textbox.

    Does this mean your processing the text in some way before you give it to the plugin? Could you document this?

  • Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

  • Whatever I type in the “Try it” textbox, I don’t get any suggestion. Pl let me know how to see the demo.