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. 60
    Facebook style inputs :: Jaz-Lounge « Says:

    [...] just read about an autocompletion input mechanism in mootools like that used in facebook. This is a really cool way to add names from a list to your query or [...]

  2. 59
    SiNi Daily » Blog Archive » Facebook Style Input Box Says:

    [...] Guillermo Rauch set out to build something similar and he did a very good job of mimicking this behavior using MooTools v1.2: [...]

  3. 58
    EGBlue Says:

    @Marcel
    Nice suggestions. How exactly can you employ Binary Search though in that kind of script?
    Let’s say you sort it by first name, and using Binary Search you are able to find the first name. Then you use that index to start a sequential search from that point on? Assuming you figure that out, how do you then use it for Last name?
    Obviously such a solution would be great, i’m just not sure how it can be employ.
    Thanks in advanced.

  4. 57
    Weekend Links - FancyZoom, Icon Design, PHP Desktop Applications, PHP Geocoding Using Google Maps API, LinkedIn, TextboxList AutoCompletion Says:

    [...] http://devthought.com/textboxlist-meets-autocompletion/ addthis_url = ‘http%3A%2F%2Fdavidwalsh.name%2Ffancy-zoom-icon-design-php-desktop-application-php-geocoding-google-maps-api-linkedin-autocomplete%2F’; addthis_title = ‘Weekend+Links+-+FancyZoom%2C+Icon+Design%2C+PHP+Desktop+Applications%2C+PHP+Geocoding+Using+Google+Maps+API%2C+LinkedIn%2C+TextboxList+AutoCompletion’; addthis_pub = ”; [...]

  5. 56
    Devalnor Says:

    Hi,

    I like your code style : var that = this;

    ;-)

    Anyway thanks for this. It’s a very nice one. I’ll adapted it to accept new values with other css classname for them.

    I’ll keep you in touch.

    Devalnor

  6. 55
    AXXT - Web development and more » Give you input fields Facebook look Says:

    [...] here is the author page http://devthought.com/textboxlist-meets-autocompletion/ [...]

  7. 54
    Guillermo Rauch Says:

    @Marcel
    Really interesting suggestions.. I guess I’ll have to release a new version then !
    Thanks

  8. 53
    Javascript News » Blog Archive » Facebook Style Input Box Says:

    [...] Rauch set out to build something similar and he did a very good job of mimicking this behavior using MooTools v1.2: While working on my big and exciting new project, I decided to include an input that resembles the [...]

  9. 52
    Marcel Says:

    Pretty slick… it’s missing some of the features of the Facebook control, though:
    - When you hit the up and down arrows in your, you’re not canceling the event, so your cursor moves around in the text box
    - Facebook’s searching is done with a binary search, you’re using a sequential search… you may notice some slow down after like 5000 elements
    - Facebook’s version will give you a scrollbar if more than 10 results come back. You can even hit the down arrow with nothing typed in, and it will give you the whole list. The results are rendered on a timeout so it remains quick and responsive even when enumerating thousands of results.

    I’m impressed, though!

  10. 51
    noisylime » Blog Archive » TextboxList meets Autocompletion Says:

    [...] LINK [...]

  11. 50
    Revolutions Shout Box » Blog Archive » Facebook Style Input Box Says:

    [...] Rauch has built a very useful input box script for easily adding multiple recipients for messaging purposes. Utilizing Mootools v1.2 it is only [...]

  12. 49
    flipthefrog Says:

    When running it locally, i get this error on test.js, line 170

    j has no properties

    running it on apache works

  13. 48
    Ajaxian » Facebook Style Input Box Says:

    [...] Rauch set out to build something similar and he did a very good job of mimicking this behavior using MooTools v1.2: While working on my big and exciting new project, I decided to include an input that resembles the [...]

  14. 47
    EGBlue Says:

    Hey guys, for those who are interested. A ported version of this great script into PrototypeJS can be found at http://www.interiders.com

  15. 46
    Proto!TextboxList meets Autocompletion | InteRiders Says:

    [...] is the Prototype version of the extended script by Guillermo Rauch. As with the previous script, this script has been converted and operates like the original. An [...]

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

Leave a Reply