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 27th, 2008 at 10:07 am
@Ignacio
In that case, a good idea would be to add an option to limit the number of boxes you can add. I’ll probably add it soon
January 27th, 2008 at 9:56 am
Thats ok, but the idea is use both, with a true or false, with multiple selects and without, you know what I mean
January 27th, 2008 at 6:37 am
@Ignacio
It’s not worth using this script only for autocompletion.
January 27th, 2008 at 6:22 am
I’m looking this script for only Autocompletion, without the multiple select. But no other, I want THIS script. Any help? Thanks! I’m desperate!
January 25th, 2008 at 1:16 pm
Missed out a .value after the $(’MESSAGEToNames’)
Now it works
January 25th, 2008 at 1:10 pm
Had to create the instance outside the addEvent
var tlist2 = MsgFriendsList;
window.addEvent(’domready’, function() {
// init
tlist2 = new MsgFriendsList(’MESSAGEToUser’, ‘MsgFriends-auto’);
Changed the the update function to update a hidden input
update: function() {
$(’MESSAGEToNames’) = this.bits.getValues().join(this.options.separator);
//this.element.set(’value’, this.bits.getValues().join(this.options.separator));
// return this.bits.getValues().join(this.options.separator);
},
and then just called the tlist2.Update() in my forms onsubmit
I might of been wrong to do it this way, but it works
January 25th, 2008 at 12:56 pm
Still cant get the update to fire. New to javascript
January 25th, 2008 at 8:01 am
Che, buenísimo esto, yo tambien soy de Argentina, me parece que acá esta el talento!
January 24th, 2008 at 5:03 am
@Renjith
Use the .update() method of your TextboxList instance when submitting the form.
January 24th, 2008 at 4:10 am
Very Nice One..
I integrated it with PHP
The auto sujjest is working..
But i hav a doubt
how to submit the data??
sujjested result it is not in the text box
January 23rd, 2008 at 5:28 am
Guys: if json.html doesn’t work for you, change the url to something that does. Remember it’s only intended as an example.
January 23rd, 2008 at 3:43 am
I’m having the same problem as “Nick” (two posts above). I can’t get the json file to load. Everything looks same as site example. Just to be safe, I copied site JS and replaced in my JS file to no relief. Any thoughts?
Thanks.
p.s. Very cool. Just need it to work for me
January 21st, 2008 at 11:07 pm
This tool is GREAT!!!
I’m using it in my site, excellent stuff. thank you very much
[note] for other who’s going to use this, there’s a bug with the mootools function .removeClass(’classname’) ; which doesn’t work in IE7 as far as i know.
simply change to .className = ”;
i’m still trying to figure out how i can set some of this options, only if there were example.
January 20th, 2008 at 4:05 pm
[...] How to create a Facebook Textbox List with auto-compeltion [...]
January 19th, 2008 at 8:23 am
Yeh I thought it would - but can’t seem to get the autocomplete to list the items in the json.html file….. only the two listed initially
“Jorge Luis Borges
Julio Cortazar”
Thanks
Nick