Jquery-ui autocomplete dropdown below each word

白昼怎懂夜的黑 提交于 2020-05-22 11:01:50

问题


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

enter image description here

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!