Autocomplete

Prehistory


First of all, I want to say, that this plugin was developed for KyivStar, therefore all fine details were studied and stipulated very carefully. For example, what should occur, when the user would reach last element of the list: whether it should rest against the end or begin a cycle all over again. Or whether the list should disappear when the cursor is out of it. All this passed through business analysts’ and designer and only then came to me.

On the other hand I tried to make autocomplete multifunctional (multipurpose) and as simple as possible for any person to use it on ones site. Remarkable is that even with switched off javascript the site would not lose functionality, and visitor can enter data anyway. Autocomplete was not made as a filtrator of data entered by the user but the tool which helps the user to fill the form more quickly.

Well-known plugin jquery.suggest was taken as an example. Pieces of which can be identified in some methods. In spite of the fact that I took mechanism, I have added some new functions and have removed some errors. So in last version jquery.suggest the code became more readable thanks to the removal of one check. But at the end of the list the cursor (illumination) disappears for one position and then again appears at the first element of the list. It happens because jquery (in traversing) always return itself to the object and doesn’t give value to quantity chosen nodes. Another authors fault that he persistently tries to apply $.fn.bgiframe to the list <ul/>, This invention is certainly noble, but I couldn’t deal with this on practice.

Functions that were added: generation of the list from select-box, the limited visible part of the list with scrolling and prefilling of the list for it to look like a select-box. One more events handling onKeyPress. Well-known algorithm of caching MRU was deleted and replaced with my cache algorithm, this takes a lot of memory but it very fast!



Downloads


Last update 24.11.2014!


Copy all this files to your own local web-server in root directory, rename search.phps to search.php and run http://path.to.your.server/autocomplete.html.



Examples


Example 1: Minimal requirements

To launch plugin you just need to put in one parameter, the url of php script which generats a list of words. Format of the list can be either xml or json.


$("#autocomplete1").autocomplete({
	url: "search.php"
});

Example 2: onSelect event

Plugin has four public events. First of them is onSelect, it fires where you pick element from the list. You can activate it by left clicking or pressing ‘enter’ button on the selected item. In this example I use one second delay before searching, and string must be at least 2 characters. The ansver from server will be in xml format so you can omit type property.


$("#autocomplete2").autocomplete({
	url: "search.php?type=xml",
	minchar: 2,
	delay: 1000, // in milliseconds
	onSelect: function (){
		alert(this.ac.val());
	},
	type: "xml"
});

Example 3: onKeyPress

onKeyPress event fires when you are typing. It can be used to filtrate user input. In this example you can use only alphabetical characters and white space, all other characters will be deleted. The fillin flag will fill in list before user start typing, because of input string is empty the request to the server will also contains empty mask value (i.e. search.php?type=json&mask=). In this case you will see list of one item with text «The list is empty!». The ansver from server will be in json format and you must set type property to ‘json’.


$("#autocomplete3").autocomplete({
	url: "search.php?type=json",
	onKeyPress: function (){
		var self = this;
		setTimeout(function () {
			self.ac.val(self.ac.val().replace(/[^a-z ]+/g, ""));
		}, 50);
	},
	fillin: true,
	type: "json"
});

Example 4: onError event

onError and onSuccess is the last two events, onError fires when AJAX has a problems otherwise onSuccess fires when you get answer from server. For example onError fires where you request for non-existing page. Also its an example of how to disable autocomplete. onSuccess get the same parametrs and scope.


$("#autocomplete4").autocomplete({
	url: "non_exist.php",
	onError: function (XMLHttpRequest, textStatus) {
		this.ac.val(textStatus);
		this.ac.attr({disabled: "disabled"}).css({"background-color": "#d0d0d0"});
		this.ul.hide();
		this.img.unbind("click");
	}
});

Example 5: generation list from <select>

All previous examples generats autocomplete from AJAX but you also can do this from html code of current page. You can replace existing select-boxes with autocomplete by using source instead of url. You can pass in plugin either string with selectors like ‘#select.class’ or jQuery object $(‘#select.class’). Pre-filling and digit-only filtrating is enable.


$("#autocomplete5").autocomplete({
	source: "#select",
	onKeyPress: function (){
		var self = this;
		setTimeout(function () {
			self.ac.val(self.ac.val().replace(/[^0-9]+/g, ""));
		}, 50);
	},
	fillin: true
});

Example 6: generation list from array

If you have no need to use AJAX or have no select-box on your page, you can generate autocomplete from array. Sorry but nested arrays are not supported so you can not use [{a:’a’},{b:’b’}]


$("#autocomplete6").autocomplete({
	source: ["a", "b", "c', "d', "e"],
	fillin: true
});

Example 7: generation list from object

The same as above. Sorry but nested objects are not supported so you can not use [{a:’a’},{b:’b’}] or {a:{b:c}}


$("#autocomplete7").autocomplete({
	source: {a: "a", b: "b", c: "c", d: "d", e: "e"},
	fillin: true
});

Example 8: list position

Example of list position at the top of input box


$("#autocomplete8").autocomplete({
	url: "search.php",
	top: true
});

Example 9: real values

Example of real values in non writeable fields


$("#autocomplete9").autocomplete({
	url: "search.php",
	values: true,
	writable: false,
	onSelect: function () {
		alert(this.pairs[this.ac.val()]);
	}
});

Example 10: alternative setup

By onSetup event you can change all properties exept ‘width’ or change behaviour of elements after autocomplete created. This example demonstrate smooth animation to options list.


$("#autocomplete10").autocomplete({
	onSetup: function () {
		var self = this;
		self.url = "search.php";
		self.img.unbind("click")
			.bind("click", function () {
				clearTimeout(self.close);
				self.scroll();
				self.ul.slideToggle("slow")
				self.ac.focus();
			});
	}
});

Example 11: progress animation

Example of real usage with event hndling and animation


$("#autocomplete11").autocomplete({
	url: "/content/polygon/search.php?type=json",
	onSuggest: function () {
		this.ac.css({"background-image": "url(progress.gif)"});
	},
	onError: function (XMLHttpRequest, textStatus) {
		this.ac.val(textStatus);
		this.ac.attr({disabled: "disabled"}).css({"background-color": "#d0d0d0", "background-image": "none"});
		this.ul.hide();
		this.img.unbind("click");
	},
	onDisplay: function (list) {
		this.ac.css({"background-image": "none"});
		if (!list) {
			this.ul.append("<div style='line-height:100px;text-decoration:underline;text-align:center;'>[Empty list...]</div>");
		}
	},
	minchar: 2,
	type: "json"
});

Example 12: custom data format

Example of how to use custom data format


$("#autocomplete12").autocomplete({
	source: [
		{a: "a"},
		{b: "b"},
		{c: "c"},
		{d: "d"},
		{e: "e"}
	],
	fillin: true,
	dataHandler: function (mask) {
		var self = this;
		return function (i, n) {
			for (var key in n) {
				self.cache[mask].push(n[key]);
			}
			self.store[mask] += self.mark(n[key], mask);
			if (self.values && !self.pairs[n[key]]) {
				self.pairs[n[key]] = key;
			}
		};
	}
});

Example 13: cascading selectbox

Example of how create selectbox wich depends on another input field


$("#autocomplete13").autocomplete({
	url: function (self) {
		var state = $("#c13").attr("checked");
		if (self.ac.data("c13") != state) {
			self.ac.data("c13", state);
			self.cache = {};
			self.store = {};
			self.pairs = {};
		}
		return "search.php?c13=" + state;
	}
});

Example 14: autocomplete form selectbox

Example of how to customize selectbox with plug-in


$("select#autocomplete14").autocomplete();

Notice

There is no simple way to re-render autocomplete created from select-box or array (object). You just need to re-create it.


Donation

If you like this plugin please vote for it on jquery site


Thanks to

  • Damir
  • Connected
  • Joey
  • Pasha
  • Morleydots
  • Gianfrasoft
  • Andrea
  • Ztalker
  • WooYek
  • Naden
  • Andrea Riciputi


Advanced options

Properties

  • url — [String|Function] ajax url
  • source — [String|jQuery|Array|Object] css selector or raw html, jQuery object, array [], object {}
  • minchar — [Integer] The minimum number of characters a user has to type before the autocompleter activates (default 1)
  • delay — [Integer] The delay in milliseconds the autocompleter waits after a keystroke to activate itself (default 50 miliseconds)
  • fillin — [Boolean] Pre-fill in (default false)
  • width — [Integer] width of autocomplete (default 200)
  • type — [String] type of server responce xml or json (default xml)
  • top — [Boolean] position of the list (default false to the bottom)
  • writable — [Boolean] allows to user write his own option (default true)
  • values — [Boolean] keep values for options (default false)
  • partial — [Boolean] makes request to server after each new letter (default false)

Events

  • onKeyPress — fires when user press a button
  • onSetup — fires once when autocomplit created
  • onSuggest — fires after onKeyPress but before ajax request send
  • onSuccess — fires when AJAX retuns result
  • onError — fires when AJAX retuns error
  • onDisplay — fires before list of items shows
  • onSelect — fires when user picks up from list

Dependences

  • jQuery — requires jQuery 1.2.6 or higher
  • bgiframe — use bgiframe if installed

100 Комментарии “Autocomplete

  1. I am trying to get autocomplete working with such JSON:

    
    [
    {"test 1": "agV0YmRwbHIWCxIQdG9iZWRvbmVfcHJvamVjdBgMDA"}, 
    {"test 2": "agV0YmRwbHIWCxIQdG9iZWRvbmVfcHJvamVjdBgSDA"}
    ]
    

    I jumping through hoops to figure out what’s wrong, maybe the format is wrong?

    Thx. WooYek.

  2. Oh, thank’s. I’ve noticed the nested objects, but must have missed the arrays part.

    Have someone done it — the array support?

  3. try to replace lines 258-274 with something like

    
    $.each(xml, function(i, n) {
        for (var key in n){
            map.push(n[key]);
            list.push(self.mark(n[key],mask));
            if(self.values && !self.pairs[n[key]])
                self.pairs[n[key]] = key;
        }
    });
    

    in case you won’t use ajax or ‘select’ to create autocomplete

  4. Еще былобы хорошо чтобы использование кнопки TAB было опционально. Так как в большинстве случаев при нажатии TAB юрез ожидает перехода в следующее поле.
    Пока пришлось грубо исправить в самом автокомплите.

  5. Еще предложение: по щелчку на стрелочку — выводить полный список элементов, независимо от вписанных значений, это более логично (или хотябы сделать опционально). Пока реализовал изменив метод «suggest».
    + при при этом проматывать до текущего выбранного элемента. Это у себя пока не смог сходу сделать =(

  6. I tried about 5 different jQuery lib’s until I found this one. It’s simply the best and does exactly what I was looking for. I did not had to change a single line.

    Small Suggestion: apply «cursor: pointer;» to «.ac_img» to have a better look and feel and maybe an optional hover effect for the image.

  7. Hi,
    I was trying out your plugin but I have a problem with all the examples on this page. When I click on the down-arrow on the right side of the field the resulting dropdown menu is always empty. No matter if I try out the AJAX or «local» examples. Any suggestion? I tried to run the demos with both Firefox 3.5.2 and Safari 4.0.2. Hope you can help me.

    TIA,
    Andrea

  8. i have test it ,if the options is more than 200,when it excute the autocomplete function,the browser cost cpu much…
    it haven’t meet my need…though its function is good…
    hope to improve

  9. Hi ! First at all…thanks for sharing it… nice coding style…! I would like to help…and I think I have found a small bug…

    bug: in «check: function (mask)» saids «if (it && !mask.indexOf(it.toLowerCase()))»
    fix: «if (it && mask && !it.indexOf(mask.toLowerCase()))» Regards

  10. hi. I’ve tryed to use your control no my website. It looks very nice.
    But I found a little problem in markup.
    When I use firefox the results window SOMETIMES renders in incorrect place. Sometimes it’s in left top corner of the screen, sometimes far at the bottom. But the same page sorks perfect in ie. do you have any ideas about this? TIA

  11. @Francisco
    «mask» is a value of your input, the «check» function is called when you check at least one character at input. so its impossible to have empty mask. dont you think so?

  12. the site is in development state. I’ve created a new account for you
    username : CTAPbIu_MABP
    password: qwerty

    In combobox at the top choose a customer «appolo», then follow to the Groups page.
    Select any group except «No group» or create a new one if you want. Then press Add button below the user grid

  13. @CTAPbIu_MABP

    CTAPbIu_MABP :
    @Francisco
    «mask» is a value of your input, the check function is called when you ензув at least one character at input. so its impossible to have empty mask. dont you think so?

    Yes it is correct !. The important is change !it.indexOf(mask.toLowerCase()) instead of !mask.indexOf(it.toLowerCase()) (I included all to make it clear), regards

  14. @Francisco
    i see :) you miss one little detail
    if you type word «ab» at first letter this.cache = {a:[…]} and at second you trying to check «a».indexOf(«ab»). you will have nothing so you should check «ab».indexOf(«a») and get array to filter.
    do we understand each other?

  15. ok, i have reproduce your bug.
    i dont have much time to test it but i think that i know the answer
    you create AC in a hidden element, i know that all hidden elements have elem.offsetHeight/Width === 0 . When AC set coordinates to list it uses formula «container.offset().top + height + border». May be this offset is also equal to 0 when element is hidden.

    So you can create AC or trigger window «resize» event ($(window).trigger(«resize»)) after container gets visible

  16. CTAPbIu_MABP :
    @Francisco
    i see :) you miss one little detail
    if you type word «ab» at first letter this.cache = {a:[…]} and at second you trying to check «a».indexOf(»ab»). you will have nothing so you should check «ab».indexOf(»a») and get array to filter.
    do we understand each other?

    That’s correct, but think in you are using a real query service in the server (not a simple array like the search.php that you include)…which behavior implicate that the results depends on the mask and one proximity algorithm, and addtionaly you want to match the mask in any position of strings (in the server results)…then in this case my code change works better for the user experience, because in this case when the server does not return result (for «ab») is very likely that «a».indexOf(»ab») return a good result for the user (I tested it)
    Regards

  17. ohhhh…
    ok, you have a point. But x.indexOf(y) [in line 240] will not solve the problem. I have another 2 place in code where i check whether words in the list begins with mask, [this are lines 250-255 and 304-305] or not.

    you made me think…

    i need some time for tests with different proximity algorithms and cache algorithms

  18. CTAPbIu_MABP :
    ohhhh…
    ok, you have a point. But x.indexOf(y) [in line 240] will not solve the problem. I have another 2 place in code where i check whether words in the list begins with mask, [this are lines 250-255 and 304-305] or not.
    you made me think…
    i need some time for tests with different proximity algorithms and cache algorithms

    Yes I know…I have ready working revision fixing all of that…is adapted for me case so include other modifications…if you provide me with you email I can send you it for your covenience…

  19. Have been using your autocomplete plugin for a while, and now encountered a problem — i need to re-attach autocomplete to an element. The situation is that it caches old values when I do it, but I need to make something so that it acts like it was just attached. Any suggestions?

    P.S. The plugin is very good :) I like it :)

  20. If you need just to clear cache you can do some thing like this

    
    $("#my_input").autocomplete({onSetup:function(){
        this.ac.bind("clearCache",this,function(e){
            var self = e.data; // autocomplete object
            self.cache = {};
            self.store = {};
            self.pairs = {};
        })
    }});
    
    $("#my_input").trigger("clearCache");
    
  21. Уже в комментах писали об этом, но вопрос остался без ответа автора…

    Как сделать так, чтобы слово находило не по первым символам, а в любом месте строки.
    Т.е. чтобы при вводе «use» находилось слово house ?

  22. Sorry but i’ve an error with the second letter in input firebug give me this error..

    self.cache[array[item]][word].toLowerCase is not a function

    i’ve implemented it with json and xml but it’s the same..anyone have a solution?

  23. Privet.
    Ludi skazhite kak sdelat sdes tak shtobi v spiske vihodilo ne 7 strok isnachalno a skazhem 20 ?

    THX.

  24. Privet vsem.
    Snaet li kto nibud kak mozhno etot script nastroit tak, shtobi poisk shel ne sleva, a po vsemu soderzhaniju?

    Naprimer est paru slov v array (v odnom kluche):

    «Nintendo N64 Basic Set Blau», v etom Scripte eto slovo proignoriruetsja t.k. ono nachinaetsja s ne «N64», a mne nado shtobi ono tozhe otobrasilos t.k. N64 predsutstvuet.

    THX.

    Cu.

  25. daykobold :
    Privet vsem.
    Snaet li kto nibud kak mozhno etot script nastroit tak, shtobi poisk shel ne sleva, a po vsemu soderzhaniju?
    Naprimer est paru slov v array (v odnom kluche):
    «Nintendo N64 Basic Set Blau», v etom Scripte eto slovo proignoriruetsja t.k. ono nachinaetsja s ne «N64», a mne nado shtobi ono tozhe otobrasilos t.k. N64 predsutstvuet.
    @CTAPbIu_ spasibo.
    THX.
    Cu.

  26. @CTAPbIu_ esli ja pravilno ponil to ti eshe rasmotrish etot sluchay ;=) ?
    I eshe nashel neobichniy bug, esli sanesti skazhem slovo n64 potom stiret ego i nabrat N64 (bolshimi bukvami), to bolshe ne vihodit okno suggest, cache kak ti vishe napisal tozhe vstroil ne pomoglo. V chem tut delo?

  27. Po povodu Cacha — isvenjaus teper vrode pashet, stranizu nado bilo perestartanut ;=)

  28. Здравствуйте,
    как можно в этом автокомплите сделать поиск по всей стоке, а не только по началу?

  29. У Меня 2 автокомплита, один генерится из массиа (source), второй с аякс запросом.
    Почему в первом случае можно вводить значения любые.. которых нет в селекте,
    а второй блокирует ввод букв значений которых нету ???

  30. еще раз выкладываю как сделать поиск по всей строке

    
           check: function (mask){
               var self = this;
               if (self.cache[mask])
                   return true; // quick return
               if(self.partial)
                   return false;
               mask = mask.toLowerCase();
               for(var it in self.cache)
                   if (it && !it.toLowerCase().indexOf(mask))
                       return true;
               return false;
           },
    
           grab: function (mask){
               var self = this, map = [], array = [];
               if (self.cache[mask])
                   return self.cache[mask]; // quick return
               for(var it in self.cache)
                   array.push(it);
               array = array.reverse();
               mask = mask.toLowerCase();
               for(var item in array)
                   if(!array[item].toLowerCase().indexOf(mask)){
                       for(var word in self.cache[array[item]])
                           if
    (!self.cache[array[item]][word].toLowerCase().indexOf(mask))
                               map.push(self.cache[array[item]][word]);
                       break;
                   }
               return map;
           },
    
           mark : function(text, mask){
               return new RegExp(mask, 'ig').test(text) ?
                   '<div>' + text.replace(new RegExp(mask, 'ig'), function(mask) {
                       return '<span class="ac_match">' + mask + '</span>';
                   }) + '</div>' : '';
           },
    
  31. Если я добавляю через javascript элемент в select, например
    window.document.getElementById(«autocomplete14»).options[0] = new Option(«ля-ля», «ля»);
    как можно после этого корректно обновить автоселект??

  32. А я могу как-то задать значение по умолчанию, чтобы оно сразу выводилось в верхней строчке?

  33. @rembrant
    насколько я помню — никак, разве что удалить его и сделать новый.

    @-=ALEX=-
    да надо на onDisplay повесить функцию которая подставит первый элемент в поле, так?

  34. я придумал как обновлять существующий автокомплит.

    
    $("input#id").autocomplete({
    	onSetup : function(){
    		var self = this;
    		self.ac.bind("refresh",null,function(){
    			self.suggest();
    		});
    	}
    });
    

    использовать

    
    $("input#id").trigger("refresh")
    

Комментарии закрыты