Focus on jQuery autocomplete result (not necessarily the first one)

I am struggling to extend jQuery autocomplete so that by default a certain object has focus. Exceptional functionality works really well, but it's not perfect. Using the parameter autoFocus

, I can automatically focus on the first element.

$( "#input" ).autocomplete({
    source: "autocomplete.php",
    minLength: 1,
    autoFocus: true
});

      

However, I would like to have more control over which element is focused. If the user enters "eng" and the relevant items my source returns:

  • American English
  • British English
  • English
  • Scottish English

I would like the third English element to be selected by default (i.e. the element that actually starts with user input, although I would like to display other results). Ideally my source - autocomplete.php - could specify which element should be the default focus.

Any ideas? I don't even know how to start.

+3


source to share


2 answers


There is a simple way to do this using an open

event. You can process the client-side code by selecting the default item, or send an extra property with the selected item. I'll consider both options:

Focus of the sentence starting with the term selected on the client:

$("input").autocomplete({
    source: /* ... */,
    open: function (event, ui) {
        var menu = $(this).data("uiAutocomplete").menu
            , i = 0
            , $items = $('li', menu.element)
            , item
            , text
            , startsWith = new RegExp("^" + this.value, "i");

        for (; i < $items.length && !item; i++) {
            text = $items.eq(i).text();
            if (startsWith.test(text)) {
                item = $items.eq(i);
            }
        }

        if (item) {
            menu.focus(null, item);
        }
    }
});

      

Basically the idea is to do the following when the autocomplete menu is open:

  • Create a regular expression to find words that start with a search term.
  • Iterate over each menu item and check its text for a regular expression. If we find a match, stop iterating and store the value.
  • If we got a value, use the focus

    method to highlight the element.

Example: http://jsfiddle.net/J5rVP/40/ (try looking for E Russian or S cots English)

The code uses a local datasource, but it should work with remote source.


Focus sentence starting with the term selected on the server



Continuing with the example above, you can customize the way the data is passed down so that on each lookup, your server-side code determines which item to select. You can do this simply by specifying an additional property for the item you want to select. For example, your JSON response might look something like this:

[{"label":"American English","select":true},{"label":"British English"},{"label":"English"},{"label":"Scots English"}]

      

Note the property select

for "American English". This indicates autocomplete that we would like to select this item by default.

Then you will update the widget initialization code to navigate to the event open

as described above. This time though we're just looking for an element with a property select

:

$("input").autocomplete({
    source: "autocomplete.php",
    open: function (event, ui) {
        var menu = $(this).data("uiAutocomplete").menu,
            i = 0,
            $items = $('li', menu.element),
            item,
            data;

        for (; i < $items.length && !item; i++) {
            data = $items.eq(i).data("ui-autocomplete-item");
            if (data.select) {
                item = $items.eq(i);
            }
        }

        if (item) {
            menu.focus(null, item);
        }
    }
});

      

Example: http://jsfiddle.net/J5rVP/42/

Please note that in the above example, American English is always selected. Since autocomplete issues a new request every time the user enters data, your server will respond to different offer data and therefore a different selected item.

Also I don't know PHP, so I can't talk about how you would add the property select

to JSON. It looks like it would be pretty simple, although it might even look like the JavaScript code in the first example that uses a regular expression.

+3


source


I suggest that you look at data mapping differently, so higher priority objects are displayed first, such as words starting with the search term.

Then you can do an autocomplete / category demo to separate your results. This will be much easier than trying to code the change autoFocus

, your top ranks will be on top and the focus will start there.

http://jqueryui.com/autocomplete/#categories

Here's a concept you could work with to rank results:

function rankResult($str, $term){
     /* 0 is first letters, 1 is in first word, 2 is starts another word, 3 is in word not first word*/
     $words=explode(' ', $str); 
     if(stripos($words[0],$term) !==false){
        return stripos($words[0],$term)==0 ? 0 : 1;
     }else{
        $rank=3;
        for( $i=1; $i< count( $words); $i++){
            if(stripos($words[$i],$term)===0){
                $rank=2;
            }
        }
        return $rank;
     }      
}

 $rank = rankResult('English', 'eng'); /*=> 0 */

      



Looping:

  array('American English','British English','English','Scots English','HasEngInIt');

      

Returns:

Array
(
    [0] => Array
        (
            [label] => American English
            [rank] => 2
        )

    [1] => Array
        (
            [label] => British English
            [rank] => 2
        )

    [2] => Array
        (
            [label] => English
            [rank] => 0
        )

    [3] => Array
        (
            [label] => Scots English
            [rank] => 2
        )

    [4] => Array
        (
            [label] => HasEngInIt
            [rank] => 1
        )

)

      

You will need to sort a little so that the data is grouped by rank before submitting to autocomplete

+1


source







All Articles