TextboxList meets Autocompletion

TextboxList Autocompletion

Demo here

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

  1. var FacebookList = new Class({
  2.  
  3. Extends: TextboxList,
  4.  
  5. data: [],
  6.  
  7. options: {
  8. onInputFocus: function() { this.autoShow(); },
  9. onInputBlur: function(el) {
  10. el.value = '';
  11. this.autoHide();
  12. },
  13. onBoxDispose: function(item) {
  14. this.autoFeed(item.$attributes.$text);
  15. },
  16. autocomplete: {
  17. 'opacity': 0.8,
  18. 'maxresults': 10,
  19. 'minchars': 1
  20. }
  21. },
  22.  
  23. initialize: function(element, autoholder, options) {
  24. arguments.callee.parent(element, options);
  25. this.autoholder = $(autoholder).set('opacity', this.options.autocomplete.opacity);
  26. this.autoresults = this.autoholder.getElement('ul');
  27. var children = this.autoresults.getElements('li');
  28. children.each(function(el) { this.add(el.innerHTML); }, this);
  29. },
  30.  
  31. autoShow: function(search) {
  32. this.autoholder.setStyle('display', 'block');
  33. this.autoholder.getElements('*').setStyle('display', 'none');
  34. if(! search || ! search.trim() || (! search.length || search.length < this.options.autocomplete.minchars ))
  35. {
  36. this.autoholder.getElement('.default').setStyle('display', 'block');
  37. this.resultsshown = false;
  38. } else {
  39. this.resultsshown = true;
  40. this.autoresults.setStyle('display', 'block').empty();
  41. this.data.filter(function(str) { return str ? str.test(search, 'i') : false; }).each(function(result, ti) {
  42. if(ti >= this.options.autocomplete.maxresults) return;
  43. var el = new Element('li').set('html', this.autoHighlight(result, search)).inject(this.autoresults);
  44. el.$attributes.$result = result;
  45. if(ti == 0) this.autoFocus(el);
  46. }, this);
  47. }
  48. },
  49.  
  50. autoHighlight: function(html, highlight) {
  51. return html.replace(new RegExp(highlight, 'gi'), function(match) {
  52. return '<em>' + match + '</em>';
  53. });
  54. },
  55.  
  56. autoHide: function() {
  57. this.resultsshown = false;
  58. this.autoholder.setStyle('display', 'none');
  59. },
  60.  
  61. autoFocus: function(el) {
  62. if(! el) return;
  63. if(this.autocurrent) this.autocurrent.removeClass('auto-focus');
  64. this.autocurrent = el.addClass('auto-focus');
  65. },
  66.  
  67. autoMove: function(direction) {
  68. if(!this.resultsshown) return;
  69. this.autoFocus(this.autocurrent['get' + (direction == 'up' ? 'Previous' : 'Next')]());
  70. },
  71.  
  72. autoFeed: function(text) {
  73. if(this.data.indexOf(text) == -1)
  74. this.data.push(text);
  75. },
  76.  
  77. autoAdd: function(el) {
  78. if(!el || ! el.$attributes.$result) return;
  79. this.add(el.$attributes.$result);
  80. delete this.data[this.data.indexOf(el.$attributes.$result)];
  81. this.autoHide();
  82. this.current.$attributes.$input.value = '';
  83. },
  84.  
  85. createInput: function(options) {
  86. var li = arguments.callee.parent(options);
  87. var input = li.$attributes.$input;
  88. input.addEvents({
  89. 'keydown': function(e) {
  90. e = new Event(e);
  91. this.dosearch = false;
  92. switch(e.code) {
  93. case Event.Keys.up: return this.autoMove('up');
  94. case Event.Keys.down: return this.autoMove('down');
  95. case Event.Keys.enter:
  96. this.autoAdd(this.autocurrent);
  97. this.autocurrent = false;
  98. this.autoenter = true;
  99. break;
  100. default: this.dosearch = true;
  101. }
  102. }.bind(this),
  103. 'keyup': function() {
  104. if(this.dosearch) this.autoShow(input.value);
  105. }.bind(this)
  106. });
  107. input.addEvent(Browser.Engine.trident ? 'keydown' : 'keypress', function(e) {
  108. if(this.autoenter) new Event(e).stop();
  109. this.autoenter = false;
  110. }.bind(this));
  111. return li;
  112. },
  113.  
  114. createBox: function(text, options) {
  115. var li = arguments.callee.parent(text, options);
  116. li.addEvents({
  117. 'mouseenter': function() { this.addClass('bit-hover') },
  118. 'mouseleave': function() { this.removeClass('bit-hover') }
  119. });
  120. li.adopt(new Element('a', {
  121. 'href': '#',
  122. 'class': 'closebutton',
  123. 'events': {
  124. 'click': function(e) {
  125. new Event(e).stop();
  126. if(! this.current) this.focus(this.maininput);
  127. this.dispose(li);
  128. }.bind(this)
  129. }
  130. }));
  131. li.$attributes.$text = text;
  132. return li;
  133. }
  134.  
  135. });
  136.  
  137. window.addEvent('domready', function() {
  138. // init
  139. var tlist2 = new FacebookList('facebook-demo', 'facebook-auto');
  140.  
  141. // fetch and feed
  142. new Request.JSON({'url': 'json.html', 'onComplete': function(j) {
  143. j.each(tlist2.autoFeed, tlist2);
  144. }}).send();
  145. });

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:

Click here to see HTML code

  1. <label>FacebookList input</label>
  2. <input type="text" value="" id="facebook-demo" />
  3. <div id="facebook-auto">
  4. <div class="default">Type the name of an argentine writer you like</div>
  5. <ul class="feed">
  6. <li>Jorge Luis Borges</li>
  7. <li>Julio Cortazar</li>
  8. </ul>
  9. </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

118 Responses to “TextboxList meets Autocompletion”

Pages: « 8 7 6 5 4 3 [2] 1 » Show All

  1. 30
    Guillermo Rauch Says:

    @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

  2. 29
    Ignacio Says:

    Thats ok, but the idea is use both, with a true or false, with multiple selects and without, you know what I mean

  3. 28
    Guillermo Rauch Says:

    @Ignacio
    It’s not worth using this script only for autocompletion.

  4. 27
    Ignacio Says:

    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!

  5. 26
    Ninja Says:

    Missed out a .value after the $(’MESSAGEToNames’)

    Now it works

  6. 25
    Ninja Says:

    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

  7. 24
    Zach Says:

    Still cant get the update to fire. New to javascript

  8. 23
    Ignacio Says:

    Che, buenísimo esto, yo tambien soy de Argentina, me parece que acá esta el talento!

  9. 22
    Guillermo Rauch Says:

    @Renjith
    Use the .update() method of your TextboxList instance when submitting the form.

  10. 21
    Renjith Says:

    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

  11. 20
    Guillermo Rauch Says:

    Guys: if json.html doesn’t work for you, change the url to something that does. Remember it’s only intended as an example.

  12. 19
    sdor Says:

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

  13. 18
    HiTMaN Says:

    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.

  14. 17
    Richard’s Blog » Blog Archive » Javascript for Beginners Says:

    [...] How to create a Facebook Textbox List with auto-compeltion  [...]

  15. 16
    Nick Light Says:

    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

Pages: « 8 7 6 5 4 3 [2] 1 » Show All

Leave a Reply