Yesterday I replaced an instance of my ComboBox widget with a jQuery Autocomplete. A sad day it was. However, I saved a JS file and a few K of download, so it was worth it. Unfortunately, it's missing a fairly important bit of functionality: the ability to order the list of options.
If you're doing an Ajax-based complete, you can obviously order the options server-side and jQuery will happily spit them out in the same order. In my case, however, the list of choices is static and fully known in the client. jQuery only provides options for "url" (the URL to request for options) and "data" (a static array of options). There's no half-way, where you can supply a function to return for the current term.
However, after spending a while digging around inside the internals of the widget, I discovered the undocumented "source" option (and it's complement, the "parse" option). It's a function that will be called to get the options for the current term. However, it seems to be undocumented, and is pretty tightly bound to the internal implementation of the widget. Specifically, your return value structure has to be the same as the structure returned by the internal "parse" method. Note this is NOT the 'parse' option I mentioned above.
If you don't supply data or a URL, the function passed as "source" will be invoked, and it's result will be either passed through the function passed as "parse" (if there is one), or returned directly. That result must be an array of objects that represent the options. Each object must have "data", "value", and "result" keys. The first is an array of row data (passed as "row" to various callbacks), the second is the display value (what would come back from "formatItem"), and the third is the result value (what would have come back from "formatResult").
Mess though this is, it does let you execute arbitrary code to build the option list, including supplying a custom order, which is what I needed. More specifically, I wanted to order tags that began with the search value before those that contained the search value in the middle. Here's my code, just for reference. "tagList" is an array of strings that are available for selection and the "tag" argument is the current value to be autocompleted.
jQuery("selector").autocomplete({ source: function(tag) { var map = { first: [], internal: [] } for (var i = 0; i < tagList.length; i++) { var pos = tagList[i].toLowerCase().indexOf(tag.toLowerCase()); if (pos >= 0) { map[pos == 0 ? "first" : "internal"].push({ data: [tagList[i]], value: tagList[i], result: tagList[i] }); } } return map.first.concat(map.internal); }, matchSubset: false // this is important })
>> matchSubset: false // this is important
Why is it important?
Peter,
It's important because you don't want jQuery to cache your results. For example, say one of your values is "catacombs", and you type a 'c' and then type an 'o'. After the first letter the value should appear near the top of the list ('catacombs' starts with 'c'), but after the second letter it shouldn't ('catacombs' doesn't start with 'co', but has one internally). If you have 'matchSubset' set to true (the default), Autocompleter won't invoke the source callback if you ADD letters (it will refilter internally). Since I want to regenerate every string, it's imperative 'matchSubset' is false.
Hi!
I am trying to get this to work, but I guess I'm doing something wrong.
Wcich version of autocomplete are you using? I suspect that the newest version don't have the source option..
Do you have a complete codesample for this?
[...] jQuery Autocomplete Mod – modification of Dylan Verheul’s jQuery Autcomplete plug-in which can limit dropdown to XX [...]
[...] jQuery Autocomplete Mod – modification of Dylan Verheul’s jQuery Autcomplete plug-in which can limit dropdown to XX [...]
[...] http://www.barneyb.com/barneyblog/2008/11/22/jquerys-autocompletes-undocumented-source-option/ [...]
Much better solution:
http://stackoverflow.com/questions/2382497/jquery-autocomplete-plug-in-search-configuration
@SenG,
I'm not sure it's a "much better solution" as it doesn't solve the same problem (it does front-only matching and no reordering), but it is a similar solution for a similar problem.