TextboxList meets Autocompletion

In my previous blogpost I explained how to extend TextboxList to add closing functionality via a link added to each box. But it was missing an important ingredient: autocompletion!
Again, all we have to do is extend the TextboxList class, override some methods, some events, and create some new ones (all prefixed by auto)
Click here to see Javascript code
var FacebookList = new Class({Extends: TextboxList,data: [],options: {onInputFocus: function() { this.autoShow(); },onInputBlur: function(el) {el.value = '';this.autoHide();},onBoxDispose: function(item) {this.autoFeed(item.$attributes.$text);},autocomplete: {'opacity': 0.8,'maxresults': 10,'minchars': 1}},initialize: function(element, autoholder, options) {arguments.callee.parent(element, options);this.autoholder = $(autoholder).set('opacity', this.options.autocomplete.opacity);this.autoresults = this.autoholder.getElement('ul');var children = this.autoresults.getElements('li');children.each(function(el) { this.add(el.innerHTML); }, this);},autoShow: function(search) {this.autoholder.setStyle('display', 'block');this.autoholder.getElements('*').setStyle('display', 'none');if(! search || ! search.trim() || (! search.length || search.length < this.options.autocomplete.minchars )){this.autoholder.getElement('.default').setStyle('display', 'block');this.resultsshown = false;} else {this.resultsshown = true;this.autoresults.setStyle('display', 'block').empty();this.data.filter(function(str) { return str ? str.test(search, 'i') : false; }).each(function(result, ti) {if(ti >= this.options.autocomplete.maxresults) return;var el = new Element('li').set('html', this.autoHighlight(result, search)).inject(this.autoresults);el.$attributes.$result = result;if(ti == 0) this.autoFocus(el);}, this);}},autoHighlight: function(html, highlight) {return html.replace(new RegExp(highlight, 'gi'), function(match) {return '<em>' + match + '</em>';});},autoHide: function() {this.resultsshown = false;this.autoholder.setStyle('display', 'none');},autoFocus: function(el) {if(! el) return;if(this.autocurrent) this.autocurrent.removeClass('auto-focus');this.autocurrent = el.addClass('auto-focus');},autoMove: function(direction) {if(!this.resultsshown) return;this.autoFocus(this.autocurrent['get' + (direction == 'up' ? 'Previous' : 'Next')]());},autoFeed: function(text) {if(this.data.indexOf(text) == -1)this.data.push(text);},autoAdd: function(el) {if(!el || ! el.$attributes.$result) return;this.add(el.$attributes.$result);delete this.data[this.data.indexOf(el.$attributes.$result)];this.autoHide();this.current.$attributes.$input.value = '';},createInput: function(options) {var li = arguments.callee.parent(options);var input = li.$attributes.$input;input.addEvents({'keydown': function(e) {e = new Event(e);this.dosearch = false;switch(e.code) {case Event.Keys.up: return this.autoMove('up');case Event.Keys.down: return this.autoMove('down');case Event.Keys.enter:this.autoAdd(this.autocurrent);this.autocurrent = false;this.autoenter = true;break;default: this.dosearch = true;}}.bind(this),'keyup': function() {if(this.dosearch) this.autoShow(input.value);}.bind(this)});input.addEvent(Browser.Engine.trident ? 'keydown' : 'keypress', function(e) {if(this.autoenter) new Event(e).stop();this.autoenter = false;}.bind(this));return li;},createBox: function(text, options) {var li = arguments.callee.parent(text, options);li.addEvents({'mouseenter': function() { this.addClass('bit-hover') },'mouseleave': function() { this.removeClass('bit-hover') }});li.adopt(new Element('a', {'href': '#','class': 'closebutton','events': {'click': function(e) {new Event(e).stop();if(! this.current) this.focus(this.maininput);this.dispose(li);}.bind(this)}}));li.$attributes.$text = text;return li;}});window.addEvent('domready', function() {// initvar tlist2 = new FacebookList('facebook-demo', 'facebook-auto');// fetch and feednew Request.JSON({'url': 'json.html', 'onComplete': function(j) {j.each(tlist2.autoFeed, tlist2);}}).send();});
It works by caching all the results from a JSON Request and feeding them to the autocompleter object. When a item is added as a box, it’ removed from the feed array, and when the box is disposed it’s added back, so that it becomes available in the list when the user types.
Another new feature is that you’ll be able to let it add boxes from the HTML directly:
<label>FacebookList input</label><input type="text" value="" id="facebook-demo" /><div id="facebook-auto"><div class="default">Type the name of an argentine writer you like</div><ul class="feed"><li>Jorge Luis Borges</li><li>Julio Cortazar</li></ul></div>
The constructor now takes new parameters to configure the autocompletion, like the minimum number of characters to trigger the dropdown, and more.
Changelog
- 0.1: initial release
- 0.2: added click support, removed $attributes use, code cleanup
Download
Click here to download the zip with code and examples
Tags: on January 12th, 2008
February 11th, 2008 at 12:31 pm
very nice autocomplete.
how can i get more than one autocomlete field on a single page to work? i cant get it.
thx
February 7th, 2008 at 9:01 am
[...] 20) TextboxList meets Autocompletion-Using autosuggest/autocomplete in a search field to allow users add or remove terms using Mootools Library. [...]
February 6th, 2008 at 9:43 pm
@EGBlue
If you have successfully translated the nice guillermo code into prototype, you re welcome
thanks
sapporro (at] gmail (dot] com
February 4th, 2008 at 8:55 pm
@Guillermo Rauch
Do you mind if i’ll start on the process of translating your code into Prototype?
Since Prototype is not compatible with Mootools, I cannot use your script, I really like it though and already have ‘pimped’ it.
I would like to know if I can translate it into Prototype, commenting that it is based on your script of course.
Thanks
- EGBlue
February 4th, 2008 at 2:48 pm
@EGBlue, can you send me the working sample code?
ozkana {at] gmail (dot} com
February 4th, 2008 at 2:30 pm
I was able to get it working simply by renaming the file from json.html to json.php, similar to nicefella’s method. Make sure you put it on your server or localhost. My suggestion is, since it acts like a dropdown select, in the JSON to have Title, and Value. they don’t have to be the same. So when clicked .update() you get the values, while the Titles are those that being displayed on the actual list.
February 4th, 2008 at 9:14 am
In ie7 it’s a error.
When you put 2 letters in a text see the next error:
The objecto not accept de property ot method.
Thank u and excuse my poor english.
February 4th, 2008 at 7:54 am
I first tried the original code itself and then Ninja’s method, but, no luck.. I can’t get the values.. Any ideas..?
P.S: I am using ASP.NET & C#
February 3rd, 2008 at 5:05 pm
[...] TextboxList meets Autocompletion-Using autosuggest/autocomplete in a search field to allow users add or remove terms using Mootools [...]
February 3rd, 2008 at 4:25 pm
@nicefella
ok. i fixed the problem by changing the name of json.html with json.asp and test.html with test.asp
now,
can s.o describe how i am going to use this “update” function to catch the items selected in the textboxlist.?
February 2nd, 2008 at 8:05 pm
hi,
this is very cool. but it didn’t work for me either although i simply uploaded the sample code to one of my hosting directories.
it doesn’t seem to fetch the items from json.html.
all i get are:
“Jorge Luis Borges
Julio Cortazar”
is this a hosting-related problem?
does this application require any other software to be installed before?
any help?
thanks.
January 30th, 2008 at 2:18 pm
Wicked. Have been looking for something like this. Saving it to my delicious right now!
January 29th, 2008 at 1:49 am
Nick, I’m having the exact same problem. it occurs because it cannot seems to open json.html, so it cannot iterate through the values. I’m not proficient with Mootools so i don’t really know how things work over there, i’m a Prototypejs guy. I was hoping somebody who is more knowledgeable with Mootools could elaborate more.
Thanks
- EGBlue
January 27th, 2008 at 5:26 pm
hello
I have changed the url many limes in test.js - - i keep getting the same error “j has no properties
[Break on this error] j.each(tlist2.autoFeed, tlist2);”
Please help
January 27th, 2008 at 11:12 am
Thanks