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
January 18th, 2008 at 8:42 pm
@Nick
This already works with an ajax -ajaj really, the last j being of json- response
January 18th, 2008 at 8:07 pm
Very nice - exactly what I’ve been looking for
I am trying to use this with an ajax response (so names are pulled in from db - any tips on how to do this would be a great help.
Thanks again
Nick
January 18th, 2008 at 1:56 am
its very nice components with mooTools!
nice and very nice;)
January 17th, 2008 at 7:55 am
@James
It actually took me longer to post the update than to code it itself… I’ve just uploaded it for you to use it in your project !
January 17th, 2008 at 7:54 am
[...] New! TextboxList with autocompletion [...]
January 17th, 2008 at 7:24 am
Very nice, I almost included it in my project away.
But it doesn’t seem to work when you click on one of the names in the drop down list, only when you use press enter. (Firefox 2.11, Windows XP)
Is this on purpose or something that was overlooked?
January 16th, 2008 at 4:50 pm
@Nuri
Call the update function when you submit your form.
January 16th, 2008 at 11:11 am
Very useful and smart autocompletion! Simple to implement !
But, How can I catch selected items after submitting form?
January 16th, 2008 at 12:50 am
Of course the next step is to allow AJAX submissions for items not in the autocomplete list (on enter key).
Looks awesome!
January 15th, 2008 at 9:59 pm
[...] input’un aynısını yapmış. Gayet kullanılşı olmuş. Hatta başka bir örneğinde, bunu autocomplate özelliği ile de birleştirmiş ve tadından yenmez bir web kontrolüne [...]
January 14th, 2008 at 8:43 am
[...] Guillermo me avisa de que ha terminado la versión con automplete de TextBoxList. [...]
January 14th, 2008 at 5:55 am
thanks for such cool thing!
January 13th, 2008 at 5:45 pm
[...] read more | digg story [...]
January 13th, 2008 at 5:00 pm
This is brilliant.
Very slick and it seems to just work like you’d expect… Very neat, this definately has lots of potential.
January 13th, 2008 at 6:34 am
[...] input’un aynısını yapmış. Gayet kullanılşı olmuş. Hatta başka bir örneğinde, bunu autocomplate özelliği ile de birleştirmiş ve tadından yenmez bir web kontrolüne [...]