Prevent Jquery autocomplete options from closing after each selection

Viewed 23516

I am using Jquery UI's autocomplete for multiple selectable values. All is good except the list of options closes after each selection. I would like the options to stay open until the user decides they are done making selections. I have looked through the documentation and I don't see any way to keep the options open. Any ideas?

<meta charset="utf-8">

<script>
$(function() {
    var availableTags = [
        "ActionScript",
        "AppleScript",
        "Asp",
        "BASIC",
        "C",
        "C++",
        "Clojure",
        "COBOL",
        "ColdFusion",
        "Erlang",
        "Fortran",
        "Groovy",
        "Haskell",
        "Java",
        "JavaScript",
        "Lisp",
        "Perl",
        "PHP",
        "Python",
        "Ruby",
        "Scala",
        "Scheme"
    ];
    function split( val ) {
        return val.split( /,\s*/ );
    }
    function extractLast( term ) {
        return split( term ).pop();
    }

    $( "#tags" ).autocomplete({
        minLength: 0,
        source: function( request, response ) {
            // delegate back to autocomplete, but extract the last term
            response( $.ui.autocomplete.filter(
                availableTags, extractLast( request.term ) ) );
        },
        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>
Tag programming languages:
16 Answers

Just ran into this issue myself. Here is a simple one liner for you all, just throw it into autocomplete's options.

$ac.autocomplete({
  ...
  close: function () { $('.ui-autocomplete').show() }
});

If you want to close it or if you want it to fade out when closing then you can remove the close statement or simply add .fadeOut() to the end, respectively.

$ac.autocomplete({
  ...
  close: function () { $('.ui-autocomplete').show().fadeOut() }
});

I am integrating a bootstrap jquery ui project, and I have done the opening and closing principles here.

$.widget('ui.' + internalComplete, $.ui.autocomplete, {
    options: {
        cancelClose: function(event, ui) {
            return false;
        }
    },
    close: function( event ) {
        if (!this._trigger('cancelClose', event, { ui: this.menu.element })) {
            this._super( event );
        }
    }
});

The second step is to choose to close according to the conditions

        this.uiEl = this.element[internalComplete](
            {
                minLength: 0,
                focus: opts.focus,
                select: opts.select,
                cancelClose: function(event, ui) {
                    var hasMenuItem = _applyOriginalEvent(event, function(e) {
                        return $(e.target).hasClass('ui-menu-item') || null;
                    });
                    return hasMenuItem === true;
                }
            }
        )[internalComplete]('instance');

/** * Created by GaoZuo on 2019/12/25. */

(function($) {

    var internalComplete = 'card-internalAutocomplete';
    var _uuid = 0;

    function _applyOriginalEvent(event, fn) {
        var ret = fn(event);
        if (ret == null) {
            var oe = event.originalEvent;
            if (oe != null) {
                return _applyOriginalEvent(oe, fn);
            }
        }
        return ret;
    }

    $.widget('ui.' + internalComplete, $.ui.autocomplete, {
        options: {
            cancelClose: function(event, ui) {
                return false;
            }
        },
        close: function( event ) {
            if (!this._trigger('cancelClose', event, { ui: this.menu.element })) {
                this._super( event );
            }
        }
    });

    $.widget('ui.card-autocomplete', {
        options: {
            source: null,
            link: ' a.card-link',
            /* source: [
                {
                    title: 'title',
                    subtitle: 'Card subtitle',
                    desc: 'Some quick example text to build on the card title and make up the bulk of the cards content.',
                    'group-prefix': 'js',
                    groups: [
                        {
                            value: "sizzlejs",
                            label: "Sizzle JS",
                            desc: "a pure-JavaScript CSS selector engine",
                            icon: "sizzlejs_32x32.png"
                        }
                    ]
                }
            ],*/
            focus: $.noop,
            select: function(event, ui) {
                return false;
            }
        },
        _create: function() {
            var that = this,
                opts = this.options;

            this.uiEl = this.element[internalComplete](
                {
                    minLength: 0,
                    focus: opts.focus,
                    select: opts.select,
                    cancelClose: function(event, ui) {
                        var hasMenuItem = _applyOriginalEvent(event, function(e) {
                            return $(e.target).hasClass('ui-menu-item') || null;
                        });
                        return hasMenuItem === true;
                    }
                }
            )[internalComplete]('instance');

            this._on(this.element, {
                focus: function(event) {
                    this.uiEl.search(null, event);
                }
            });

            $.extend(this.uiEl, {
                _renderMenu: function(ui, items) {
                    $.each(opts.source, function(i, n) {
                        that._createCards($('<li>').appendTo(ui), n, items);
                    });
                }
            });

            this.uiEl.menu.option('items', this.options.link);
            this._initSource();
        },

        _initSource: function() {
            var data = this.options.source;
            if ($.isArray(data)) {
                this.setSource(this._dataToSource(data));
            }
        },

        _setOption: function(key, value) {
            this._super( key, value );
            if ( key = 'source') {
                this._initSource();
            }
        },

        setSource: function(array) {
            this.uiEl.option('source', array);
        },

        _dataToSource: function(data) {
            var array = [];
            var that = this;
            $.each(data, function(i, n) {
                that._initData(array, n);
            });
            return array;
        },

        _initData: function(array, group) {
            if ($.isArray(group.groups)) {
                var prefix = group.prefix =
                    ( group.prefix || $.ui['card-autocomplete'].getPrefix( true ) );
                $.each(group.groups, function(i, n) {
                    n._prefix = prefix;
                    array.push(n);
                });
                delete group.groups;
            }
        },

        _createCards: function(li, n, list) {
            var body = $('<div>').addClass('card-body');
            li.append( $('<div>').addClass('card').append(body) );
            if (n.title != null) {
                body.append( $('<h5>').addClass('card-title').text(n.title) );
            }
            if (n.subtitle != null) {
                body.append( $('<h6>').addClass('card-subtitle mb-2 text-muted').text(n.subtitle) );
            }
            if (n.desc != null) {
                body.append( $('<p>').addClass('card-text').text(n.desc) );
            }
            this._createList(n, list, body);
        },

        _createList: function(n, list, body) {
            var that = this;
            $.each(list, function(i, li) {
                if (li._prefix == n.prefix) {
                    that._renderLi(li, body);
                }
            });
        },
        _renderLi: function(li, body) {
            $.ui['card-autocomplete'].createLi(li)
                .appendTo( body )
                .data( "ui-autocomplete-item", li );
        }
    });

    $.extend($.ui['card-autocomplete'], {
        createLi: function(li) {
            var link = $('<a>').addClass('card-link').prop('href', '#').text(li.label);
            if (li.desc != null) {
                link.prop('title', li.desc)
            }
            if (li.value != null) {
                link.attr('data-id', li.value);
            }
            return link;
        },
        getPrefix: function(next) {
            if (next) {
                _uuid++;
            }
            return "-" + _uuid;
        }
    });
})(jQuery);

******************************html*********************************************

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>jQuery UI Autocomplete - Custom data and display</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css">
    <!--<link rel="stylesheet" href="../../demos.css">-->


    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="jquery-ui.js"></script>
    <script src="jquery.ui.cards.autocomplete.js"></script>
    <!--<script src="../../../ui/jquery.ui.core.js"></script>
    <script src="../../../ui/jquery.ui.widget.js"></script>
    <script src="../../../ui/jquery.ui.position.js"></script>
    <script src="../../../ui/jquery.ui.menu.js"></script>
    <script src="../../../ui/jquery.ui.autocomplete.js"></script>-->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    <style>
        #project-label {
            display: block;
            font-weight: bold;
            margin-bottom: 1em;
        }
        #project-icon {
            float: left;
            height: 32px;
            width: 32px;
        }
        #project-description {
            margin: 0;
            padding: 0;
        }
    </style>
    <script>
        $(function() {

            var projects = [
                {
                    title: 'Card title',
                    subtitle: 'Card subtitle',
                    desc: 'Some quick example text to build on the card title and make up the bulk of the cards content.',
                    groups: [
                        {
                            value: "jquery",
                            label: "jQuery",
                            desc: "the write less, do more, JavaScript library",
                            icon: "jquery_32x32.png"
                        },
                        {
                            value: "jquery-ui",
                            label: "jQuery UI",
                            desc: "the official user interface library for jQuery",
                            icon: "jqueryui_32x32.png"
                        }
                    ]
                },
                {
                    title: '第二个分组',
                    subtitle: '第二个分组.....',
                    desc: '第二个分组的描述....',
                    groups: [
                        {
                            value: "sizzlejs",
                            label: "Sizzle JS",
                            desc: "a pure-JavaScript CSS selector engine",
                            icon: "sizzlejs_32x32.png"
                        }
                    ]
                }
            ];

            var ele = $( "#project" )['card-autocomplete']({
                minLength: 0,
                source: projects,
                focus: function( event, ui ) {
                    return false;
                },
                select: function( event, ui ) {
                    return false;
                }
            });


        });
    </script>
</head>
<body>

<div id="project-label">Select a project (type "j" for a start):</div>
<img id="project-icon" src="../images/transparent_1x1.png" class="ui-state-default" alt="">
<input id="project" class="w-50">
<input type="hidden" id="project-id">
<p id="project-description"></p>

<div class="demo-description">
    <p>You can use your own custom data formats and displays by simply overriding the default focus and select actions.</p>
    <p>Try typing "j" to get a list of projects or just press the down arrow.</p>
</div>










</body>
</html>
Related