问题
I am struggling to extend jQuery autocomplete so that a particular item has focus by default. The out-of-the-box functionality works pretty well, but it's not perfect. Using the autoFocus
option I can automatically focus on the first item.
$( "#input" ).autocomplete({
source: "autocomplete.php",
minLength: 1,
autoFocus: true
});
However, I would like to have more control over which item is focused. If the user types in "eng" and the relevant items that my source returns are:
- American English
- British English
- English
- Scots English
I would like the third item, English, to be in focus by default (i.e., the item that actually begins with the user's input, even though I would like to display the other results). Ideally my source - autocomplete.php - would be able to indicate which item is to be the default focus.
Any ideas? I'm not even sure how to start.
回答1:
There's a simple way to accomplish this, leveraging the open event. You can have client side code handle choosing the default item, or send down an extra property with the item you want selected. I'll go over both options:
Focus of suggestion starting with term, selected on 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's menu is open:
- Build a regular expression to look for words starting with the search term.
- Iterate over each menu item and test its text against the regular expression. If we find a match, stop iterating and store the value.
- If we retrieved a value, use the focus method on menu to highlight the item.
Example: http://jsfiddle.net/J5rVP/40/ (Try searching for English or Scots English)
The code uses a local data source but it should work just as well with a remote source.
Focus of suggestion starting with term, selected on server
Extending on the above example, you could tweak the way you're sending data down, so that on each search your server-side code decides which item to select. You can do this by simply specifying an additional property on the item you wish to have selected. For example, your JSON response could look something like this:
[{"label":"American English","select":true},{"label":"British English"},{"label":"English"},{"label":"Scots English"}]
Note the select
property on "American English." This indicates to autocomplete that we'd like to select that item by default.
Then you would update your widget initialization code to tap into the open
event like above. This time though we're just searching for an item with the select
property:
$("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/
Note that in the above example American English is always selected. Since autocomplete issues a new request each time the user types, your server would respond with different suggestion data and therefore a different selected item.
Also I don't know PHP so I can't speak to how you would implement adding the select
property to the JSON. Seems like it would be pretty simple though, and might even look like the JavaScript code in the first example that uses a regular expression.
回答2:
I suggest that you should look at mapping data differently so higher priority items are displayed first such as words that start with the search term.
You could then follow the AutoComplete/categories demo to separate your results. This will be a lot easier than trying to create code to change autoFocus
, your higher ranks would be at top and focus would 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 over :
array('American English','British English','English','Scots English','HasEngInIt');
Returned:
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 would have to do a little sorting so data is grouped by rank before being sent to autocomplete
来源:https://stackoverflow.com/questions/14572817/focus-on-a-jquery-autocomplete-result-not-necessarily-the-first