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).
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
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