8

I'm implementing a AJAX autocomplete/autosuggest feature, and not only do I want to do the usual show suggestions that are similar to what the user typed, but I'd like to let the user do partial completions to save typing.

So, imagine my dictionary has these values in it: "green apple", "green pear", "green fruit", "blue sky", "blue water", "blue wake".

If the user types in "g", the suggestions should be "green apple", "green pear", "green fruit", and I'd like to let the user hit TAB or something to update his query to "green ", then they could type "a" and they'd get completed to "green apple".

I'm trying to model this after linux shell command line completion.

Can you recommend a control/script that does this? Or a modification/customization of an existing control?

tshepang
  • 12,111
  • 21
  • 91
  • 136
waterlooalex
  • 13,642
  • 16
  • 78
  • 99
  • Although I cannot think of a thorough solution at the moment, I feel jQuery might be a good way to get started with. Auto-completion is not so difficult since you can always assign listener to that particular key stroke(TAB). So my personal answer is yes. – Michael Mao Dec 03 '09 at 04:08
  • I can suggest how to do it, but I don't know of a control to do it. – James Black Dec 03 '09 at 04:39
  • Hmm, how about a control that could be customized to do it? I'm sure rolling your own basic autocomplete is not that hard, but its all the edge cases I worry about :) – waterlooalex Dec 03 '09 at 14:25
  • 1
    Tab might be an issue as it generally switched focus, no? – Moshe Dec 09 '09 at 05:28
  • 1
    @Moshe: I don't think so, the stackoverflow autofill for tags uses tab, e.g. if you type in py and hit tab it autofills to python. This is similar to what I'm looking for, but I want to autofill just the number of characters common to all choices. – waterlooalex Dec 09 '09 at 05:57

3 Answers3

23

This specific type of autocompletion isn't supported in popular autocompletion plugins (for jQuery, Scripty...) because usually those provide a drop-down UI for choosing the wanted match.

So let's suppose we haven't got an out-of-the-box solution. Boo-ho. How hard can it be to code it up?

// takes a text field and an array of strings for autocompletion
function autocomplete(input, data) {
  if (input.value.length == input.selectionStart && input.value.length == input.selectionEnd) {
    var candidates = []
    // filter data to find only strings that start with existing value
    for (var i=0; i < data.length; i++) {
      if (data[i].indexOf(input.value) == 0 && data[i].length > input.value.length)
        candidates.push(data[i])
    }

    if (candidates.length > 0) {
      // some candidates for autocompletion are found
      if (candidates.length == 1) input.value = candidates[0]
      else input.value = longestInCommon(candidates, input.value.length)
      return true
    }
  }
  return false
}

// finds the longest common substring in the given data set.
// takes an array of strings and a starting index
function longestInCommon(candidates, index) {
  var i, ch, memo
  do {
    memo = null
    for (i=0; i < candidates.length; i++) {
      ch = candidates[i].charAt(index)
      if (!ch) break
      if (!memo) memo = ch
      else if (ch != memo) break
    }
  } while (i == candidates.length && ++index)

  return candidates[0].slice(0, index)
}

Test page here — it should work in normal browsers. For supporting IE use event listening from prototype.js, jQuery or other.

mislav
  • 14,919
  • 8
  • 47
  • 63
  • This is awesome. Nice script. – Jeff Rupert Dec 16 '09 at 16:35
  • 2
    The test page is no longer available. :( – Travis Bear Jul 21 '17 at 17:18
  • 3
    @TravisBear and anyone who's trying to display the test page / demo: it has been preserved by the Internet Archive [at this URL](https://web.archive.org/web/20110716170457/http://mislav.net/scripts/autocomplete.html). TIP: to find old web pages, prepend the archive.org URL to the broken URL like this: `https://web.archive.org/*/http://your-broken-url.com/nolongeravailable.html` – Jan Gondol Mar 02 '19 at 05:15
3

If your using jQuery, a great plugin is http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/. Simply use css to hide the dropdown box, and leave the tab-auto-complete functionality on.

I think it would be simple to make a jquery plugin for yourself...

Along the lines of Listen for the Tab Key When the tab key is pressed, trigger tab:press on input.autotab

   $(document).keydown(function(e){ if (e.keyCode = (tab-key?)){
       $('input.autotab').trigger('tab:press');
   });      

Bind input.autotab's tab:press event (in an each loop... if focus==true etc.) to either a javascript array lookup, or a xhr request, (ajax), then set that input's value as the returned data.

  $('input.autotab').bind('tab:press', function(){
      if (this.hasFocus){
         this.disabled = true;
         $.get('/autotab', { q: $(this).val() }, function(response){
               $(this).val(response);
               this.disabled = false;
         }, function(){ this.disabled = false; });
      }
  });

In your autosuggest script, write it so once the value is matched more than once in the database (use a for loop with an index, stopping at the index element where the first element is matched), and return the value up to that point.

CodeJoust
  • 3,760
  • 21
  • 23
1

The simplest way would be to just use the jQuery and the autocomplete plugin. Looking the the stackoverflow html, it seems that they are using the same stuff. Seems to work very well for most browsers. The plugin also has an extensive demo that should help you figure out how to implement it to your specific needs.

Here's a quick sample from the plugin home page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
                "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <link rel="stylesheet" href="http://dev.jquery.com/view/trunk/plugins/autocomplete/demo/main.css" type="text/css" />
  <link rel="stylesheet" href="http://dev.jquery.com/view/trunk/plugins/autocomplete/jquery.autocomplete.css" type="text/css" />
  <script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/autocomplete/lib/jquery.bgiframe.min.js"></script>
  <script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/autocomplete/lib/jquery.dimensions.js"></script>
  <script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/autocomplete/jquery.autocomplete.js"></script>
  <script>
  $(document).ready(function(){
    var data = "Core Selectors Attributes Traversing Manipulation CSS Events Effects Ajax Utilities".split(" ");
    $("#example").autocomplete(data);
  });
  </script>

</head>
<body>
  API Reference: <input id="example" /> (try "C" or "E")
</body>
</html>

More to be found here http://docs.jquery.com/Plugins/Autocomplete

Matti Lyra
  • 12,828
  • 8
  • 49
  • 67
  • While I did not check the code, at least [that webpage](http://docs.jquery.com/Plugins/Autocomplete) does not support completion on the suggested candidates as requested by the Q. – cfi Sep 10 '15 at 12:47