Justin Grant
Justin Grant

Reputation: 46763

autocomplete of words in the middle (jQuery UI)

Anyone know good sample code using jQuery UI's autocomplete widget that can autocomplete words in the middle of a text box, not just autocomplete of the word at the end only?

I'm using the jquery UI autocomplete widget for a component that supports entry of multiple tags. It's like like stack overflow's tag editor, but simpler: no fancy formatting in the autocomplete dropdown, no "tag" background images in the edit box. I started with the jQuery UI Autocomplete Multiple sample and modified it.

It's working OK, except autocomplete doesn't work for tags in the middle of a multi-tag string. For example, if I type C Fortran and then put the caret right after C and type +, I'd expect to see C++ in the autocomplete list but instead I see Fortran again.

Here's the code so far: http://jsfiddle.net/WCfyB/4/

This is the same problem described by autocomplete in middle of text (like Google Plus), but the problem in that question was simpler because he could rely on an empty @ in the text to signal when to show the autocomplete. In my case, I can't just rely on the text-- I actually need to find out where the caret is and autocomplete for the word where the caret is.

I could build this myself using caret or another plugin, but was wondering if there was already a jQuery-UI-based sample online that I could use without re-inventing another wheel, especially if there are browser-specific corner cases to worry about. Ideally, it'd behave like this: whenever the user places the caret inside or at the end of a tag (where tags are always separated by 1+ spaces), autocomplete is shown for that tag. Know a good sample?

Upvotes: 4

Views: 2150

Answers (1)

Andrew Whitaker
Andrew Whitaker

Reputation: 126072

I don't know of any examples like this, but here's something that you could start with:

var availableTags = [ ... ]; 

function split(val) {
    return val.split(/ \s*/);
}

function extractLast(term) {
    return split(term).pop();
}

$("#tags")
    .bind("keydown", function(event) {
        // don't navigate away from the field on tab when selecting an item
        if (event.keyCode === $.ui.keyCode.TAB
                                   && $(this).data("autocomplete").menu.active) {
            event.preventDefault();
        }
    })
    .autocomplete({
        minLength: 0,
        source: function(request, response) {
            var results = [],
                selectionStart = this.element[0].selectionStart
                term = extractLast(request.term.substring(0, selectionStart));

            if (term.length > 0) {
                results = $.ui.autocomplete.filter(availableTags, term);
            }
            response(results);
        },
        focus: function() {
            return false; // prevent value inserted on focus
        },
        select: function(event, ui) {
            var terms = split(this.value.substring(0, this.selectionStart));
            terms.pop();  // remove the current input
            terms.push(ui.item.value);        // add the selected item
            this.value =
                $.trim(terms.join(" ") + this.value.substring(this.selectionStart)) + " ";
            return false;
        }
    });

Example: http://jsfiddle.net/WCfyB/7/

The major caveat here is that the selectionStart method does not work in IE. You can replace those function calls with one of those plugins you mentioned in your question.

Upvotes: 5

Related Questions