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. 45
    danny Says:

    very nice autocomplete.

    how can i get more than one autocomlete field on a single page to work? i cant get it.
    thx

  2. 44
    Ajax Araçları : vBMaster.Org Seo Yarışması Says:

    [...] 20) TextboxList meets Autocompletion-Using autosuggest/autocomplete in a search field to allow users add or remove terms using Mootools Library. [...]

  3. 43
    sapporo Says:

    @EGBlue

    If you have successfully translated the nice guillermo code into prototype, you re welcome

    thanks

    sapporro (at] gmail (dot] com

  4. 42
    EGBlue Says:

    @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

  5. 41
    Ozkan Says:

    @EGBlue, can you send me the working sample code?
    ozkana {at] gmail (dot} com

  6. 40
    EGBlue Says:

    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.

  7. 39
    xavo Says:

    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.

  8. 38
    Ozkan Says:

    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#

  9. 37
    Best of Ajax, Dhtml and Javascript- part1 Says:

    [...] TextboxList meets Autocompletion-Using autosuggest/autocomplete in a search field to allow users add or remove terms using Mootools [...]

  10. 36
    nicefella Says:

    @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.?

  11. 35
    nicefella Says:

    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.

  12. 34
    Foxinni - Wordpress Designer Says:

    Wicked. Have been looking for something like this. Saving it to my delicious right now!

  13. 33
    EGBlue Says:

    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

  14. 32
    Nick Says:

    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

  15. 31
    Ignacio Says:

    Thanks

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

Leave a Reply