问题
I'm using Autocomplete from jquery-ui. In the multiple values, you can get dropdown list for each word after space, but the dropdown appears at the size of the input box. Is it possible to make the dropdown appear below the cursor of each which has a width equivalent to the dropdown words and not the entire length of the input box?
EDIT: Example (Google-like search box):
When you go to google and enter a long sentence as the sentence goes on, after each word, an autocomplete dropdown appears for each single word below the cursor position. So I require a similar dropdown which can be added on to the jQuery Autocomplete
My function is this big because it has features of multiple words and displaying array in order of alphabets.
Here is the <script
code:
<script>
$(function() {
var availableTags = <?php echo json_encode($sometags); ?>;
function split( val ) {
return val.split( / \s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$( "#query" )
// don't navigate away from the field on tab when selecting an item
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
minLength: 1,
source: function( request, response ) {
// delegate back to autocomplete, but extract the last term
response( $.ui.autocomplete.filter(
availableTags, extractLast( request.term ) ) );
var term = $.ui.autocomplete.escapeRegex(request.term)
, startsWithMatcher = new RegExp("^" + term, "i")
, startsWith = $.grep(availableTags, function(value) {
return startsWithMatcher.test(value.label || value.value || value);
})
, containsMatcher = new RegExp(term, "i")
, contains = $.grep(availableTags, function (value) {
return $.inArray(value, startsWith) < 0 &&
containsMatcher.test(value.label || value.value || value);
});
response(startsWith.concat(contains));
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( " " );
return false;
}
});
});
</script>
EDIT: Just like the google-box, the dropdown should contain within the width of the input box meaning for example, the dropdown box for the last word in the input box should resize not to the right but to the left. The right edge of the dropdown box should be in line with the right edge of the inputbox and the total width of the dropdown (in case of words as big or bigger than input box) should not exceed the width of the input box.
UPDATE:
Here is the final mod of the google-like autocomplete: Fiddle (Updated 16/2/2013)
Features:
1) Fixed multiple words sort alphabetically against suggestions (jQuery-ui autocomplete multiple values sort results alphabetically)
2) Retrieve suggestions from 2 arrays with first suggestion opening at full width of input box like in google and rest of suggestions at the width of the longest suggestion
3) Fixed bugs of dropdown opening before input of word after 'space' (multiple values).
4) Prevent dropdown from being kept open at the end while adding words in between.
5) 16/2/2013 Update: When the length of tags inputted from suggestion box exceeds the length of the input box and on input of the next tag, the input box displays tags from first or it moves back to the first tag position and not from where the cursor was last placed as seen here - http://jqueryui.com/autocomplete/#multiple. This has been fixed.
This is a similar fiddle with only ONE array used and suggestions always at width of the longest suggestion - FIDDLE
Thanks to Jeffery To who provided the main solution to the question, and to Vadim and Dom whose answers provided ideas that were useful in creating the above mod.
回答1:
As the other answers have suggested, we measure the width of the text in the input field (using a hidden element), then offset the autocomplete box. We can also reset the width of the autocomplete box so that it's only as wide as the longest suggestion (demo):
open: function( event, ui ) {
var input = $( event.target ),
widget = input.autocomplete( "widget" ),
style = $.extend( input.css( [
"font",
"border-left",
"padding-left"
] ), {
position: "absolute",
visibility: "hidden",
"padding-right": 0,
"border-right": 0,
"white-space": "pre"
} ),
div = $( "<div/>" ),
pos = {
my: "left top",
collision: "none"
},
offset = -7; // magic number to align the first letter
// in the text field with the first letter
// of suggestions
// depends on how you style the autocomplete box
widget.css( "width", "" );
div
.text( input.val().replace( /\S*$/, "" ) )
.css( style )
.insertAfter( input );
offset = Math.min(
Math.max( offset + div.width(), 0 ),
input.width() - widget.width()
);
div.remove();
pos.at = "left+" + offset + " bottom";
input.autocomplete( "option", "position", pos );
widget.position( $.extend( { of: input }, pos ) );
}
Update: Fixed autocomplete box positioning
Update 2: Another autocomplete box positioning fix
回答2:
Using JQuery's multiple demo, what you could do is create a hidden span element
<span id="characterSpan" style="visibility: hidden;"></span>
and use it to store the input's val()
.
From there, use .width()
to get the span's width and use the autocomplete's open( event, ui )
event :
open: function( event, ui ) {
var span = $('#characterSpan');
var width = span.width();
width > $('#query').width() ?
width = parseInt($('#query').position().left + $('#query').width()) :
width = parseInt($('#query').position().left + width);
$('.ui-autocomplete.ui-menu').css('left', width + 'px');
}
DEMO: http://jsfiddle.net/dirtyd77/5ySF9/8/
Hope I explained this well enough and let me know if you have any questions!
回答3:
I've based the answer on the answer to this question. As mentioned in that answer, IE<9 will need some extra code to make this work.
Basically you create a span into which you write out the contents of the input element. You then use the width of this span to calculate the offset. JqueryUI provides a position hook where you can actually offset the value. so the HTML
<input id="query" style="width: 300px" />
<span id="faux" style="display:none" />
And the JS
var query= $("#query");
var faux = $("#faux");
query.autocomplete({
source: mySource
}).on("keydown", function() {
var off = query.selectionStart;
faux.text(query.val().substring(0, off).replace(/\s/g, "\u00a0"));
query.autocomplete("option", "position",
{my: "left top", at: "left+" + faux.outerWidth() + " bottom"});
});
Working JSFiddle
来源:https://stackoverflow.com/questions/14672433/jquery-ui-autocomplete-dropdown-below-each-word