views:

1496

answers:

5

I'm looking into using jQuery autocomplete plug-in to implement user lookup by first or last name. It looks like by default autocomplete looks up words by character sequence no matter its occurrence in a word. So if you have data such as: javascript, asp, haskell and you type in 'as' you will get all three. I would like it to at least match beginning of the word. So in above example you get only 'asp'. Is there a way to configure jQuery Autocomplete plug-in to do this?

Ultimately it would be even better to match by beginning of first or last name like it is in Gmail.

Note: I'm trying to figure out a way to do this using jQuery UI plug-in speciifically. Since I'm already using jQueryUI plug-in in my project, I'm planning to stick with it and try not adding additional plug-ins to my web application.

+3  A: 

I use the autocomplete from devbridge. http://www.devbridge.com/projects/autocomplete/jquery/

It matches on the beginning characters, only.

alt text

As far as matching based on first name or last name, you'd just have to supply a lookup list with the first and last name.

Example usage:

  var wordlist = [
      'January', 'February', 'March', 'April', 'May', 'June',
      'July', 'August', 'September', 'October', 'November',
      'December' ]; 

      var acOptions = {
          minChars:2,
          delimiter: /(,|;)\s*/, // regex or character
          maxHeight:400,
          width:300,
          zIndex: 9999,
          deferRequestBy: 10, // miliseconds

          // callback function:
          onSelect: function(value, data){
              //$('#input1').autocomplete(acOptions);
              if (typeof data == "undefined") {
                  alert('You selected: ' + value );
              }else {
                  alert('You selected: ' + value + ', ' + data);
              }
          },

          // local autosuggest options:
          lookup: wordlist
      };

The lookup option that you pass to initialize the autocomplete control can be a list, or an object. The above showed a simple list. If you want some data attached to the suggestions that get returned, then make the lookup option an object, like this:

var lookuplist = {
    suggestions:   [ "Jan", "Feb", "Mar", "Apr", "May" ],
    data :         [ 31, 28, 31, 30, 31, ]
};
Cheeso
Cheeso thanks for your input, it is helpful. Since I'm already using jQueryUI plug-in in my project, I'm planning to stick with it and try not adding additional plug-ins to my web application.
dev.e.loper
That makes sense. In that case you might consider making a one-off modification of the jQuery UI source, to fit your requirements. I did that to fix several bugs I encountered, that are fixed in as-yet-unreleased versions. Might make sense for you, too.
Cheeso
ps: I didn't realize that the autocomplete plugin was first included in jQueryUI in v1.8. I have and use v1.7.2.
Cheeso
A: 

There’s another jQuery autocomplete plug-in that optionally searches just at the start of each item (the option is matchContains=false, I think that’s the default too).

Given the absence of such an option in the jQuery UI plugin, I’m guessing you’ll either have to use a different plugin, or rewrite the one you’re using now.

Paul D. Waite
No, he won't have to rewrite jQueryUI to get autocomplete. There's an option to do what he wants. see my answer. http://stackoverflow.com/questions/2382497/jquery-autocomplete-plug-in-search-configuration/2405109#2405109
Cheeso
Ah, bravo. You say it’s in jQuery UI 1.8 — is that out yet?
Paul D. Waite
As far as I know jQueryUI v1.8 is listed at rc3. "Release Candidate #3". Normally an RC is a pretty stable release, pretty near final. That's normally. I don't know about jQuery's release ratings practices.
Cheeso
Kewl, nearly there then.
Paul D. Waite
A: 

Where are you getting the data to populate the autocomplete? Is it from a database? If so, you can do what you want in your query and only return results that match the beginning of each word (first/last name)

Mark
+9  A: 

In jQuery UI v1.8rc3, the autocomplete widget accepts a source option which can be either a string, an array, or a callback function. If it's a string, autocomplete does a GET on that URL to get options/suggestions. If an array, autocomplete does a search, as you pointed out, for the presence of the typed chars in any position in the terms of the array. The final variant is what you want - the callback function.

From the autocomplete documentation:

The third variation, the callback, provides the most flexibility, and can be used to connect any data source to Autocomplete. The callback gets two arguments:

• A request object, with a single property called "term", which refers to the value currently in the text input. For example, when the user entered "new yo" in a city field, the Autocomplete term will equal "new yo".
• A response callback, which expects a single argument to contain the data to suggest to the user. This data should be filtered based on the provided term, and can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties).

Example code:

var wordlist= [ "about", "above", "across", "after", "against",
                "along", "among", "around", "at", "before", 
                "behind", "below", "beneath", "beside", "between", 
                "beyond", "but", "by", "despite", "down", "during", 
                "except", "for", "from", "in", "inside", "into", 
                "like", "near", "of", "off", "on", "onto", "out", 
                "outside", "over", "past", "since", "through", 
                "throughout", "till", "to", "toward", "under", 
                "underneath", "until", "up", "upon", "with", 
                "within", "without"] ; 

$("#input1").autocomplete({
    // The source option can be an array of terms.  In this case, if
    // the typed characters appear in any position in a term, then the
    // term is included in the autocomplete list.
    // The source option can also be a function that performs the search,
    // and calls a response function with the matched entries.
    source: function(req, responseFn) {
        var re = $.ui.autocomplete.escapeRegex(req.term);
        var matcher = new RegExp( "^" + re, "i" );
        var a = $.grep( wordlist, function(item,index){
            return matcher.test(item);
        });
        responseFn( a );
    }
});

A few key points:

  • the call to $.ui.autocomplete.escapeRegex(req.term); That escapes the search term so that any regex-meaningful terms in the text typed by the user are treated as plain text. For example, the dot (.) is meaningful to regex. I learned of this escapeRegex function by reading the autocomplete source code.
  • the line with new Regexp(). It specifies a regexp beginning with ^ (Circumflex), which implies, it will match only when the typed characters appear at the beginning of the term in the array, which is what you wanted. It also uses the "i" option which implies a case-insensitive match.
  • the $.grep() utility just calls the provided function on each term in the provided array. The function in this case simply uses the regexp to see if the term in the array is a match for what was typed.
  • finally, the responseFn() is invoked with the result of the search.

woorking demo: http://jsbin.com/ezifi

what it looks like:

alt text

Just a note: I find the documentation on autocomplete to be pretty immature at this point. I didn't find examples that did this, and I couldn't find working doc on which .css files were necessary or which .css classes would be used. I learned all this from inspecting the code.

Cheeso
+1 for introducing jsbin.com to me :)
henchman
@cheeso: +1 Awesome answer! I was inspecting the code too and trying to figure out what exactly `escapeRegex` was for and your post explains it perfectly.
Tauren
Tauren, Glad it helped!
Cheeso
+1  A: 

thx cheeso for intrducing jsbin.com,

i extended your code to support first- and lastname matches, too.

  $("#input1").autocomplete({
      source: function(req, responseFn) {
          addMessage("search on: '" + req.term + "'<br/>");

          var matches = new Array();
          var needle = req.term.toLowerCase();

          var len = wordlist.length;
          for(i = 0; i < len; ++i)
          {
              var haystack = wordlist[i].toLowerCase();
              if(haystack.indexOf(needle) == 0 ||
                 haystack.indexOf(" " + needle) != -1)
              {
                  matches.push(wordlist[i]);
              }
          }

          addMessage("Result: " + matches.length + " items<br/>");
          responseFn( matches );
      }
  });

demo: http://jsbin.com/ufimu3/

type 'an' or 're'

henchman
works perfectly! nice.
Cheeso