jquery ui autocomplete combobox with categories

后端 未结 4 1957
谎友^
谎友^ 2020-12-10 03:54

I\'m using the jquery ui autocomplete combobox, and it\'s working great but now i\'m getting a bit greedy. I would like to be able to add categories to it. The combobox is

相关标签:
4条回答
  • 2020-12-10 04:33

    Expanding on @Jarry's suggestion, I would update your code to determine what optgroup the option belongs to. From there, you can use similar code as found on the jQueryUI website:

    (function($) {
        $.widget("ui.combobox", {
            _create: function() {
                var input, self = this,
                    select = this.element.hide(),
                    selected = select.children(":selected"),
                    value = selected.val() ? selected.text() : "",
                    wrapper = this.wrapper = $("<span>").addClass("ui-combobox").insertAfter(select);
    
                input = $("<input>").appendTo(wrapper).val(value).addClass("ui-state-default ui-combobox-input").autocomplete({
                    delay: 0,
                    minLength: 0,
                    source: function(request, response) {
                        var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
    
                        response(select.find("option").map(function() {
                            var text = $(this).text();
                            if (this.value && (!request.term || matcher.test(text))) return {
                                label: text.replace(
                                new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(request.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"),
                                value: text,
                                option: this,
                                category: $(this).closest("optgroup").attr("label")
                            };
                            //MK
                            $('#test').attr('style', 'display: none;');
                        }).get());
                    },
                    select: function(event, ui) {
                        ui.item.option.selected = true;
                        self._trigger("selected", event, {
                            item: ui.item.option
                        });
                    },
                    change: function(event, ui) {
                        if (!ui.item) {
                            var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i"),
                                valid = false;
                            select.children("option").each(function() {
                                if ($(this).text().match(matcher)) {
                                    this.selected = valid = true;
                                    return false;
                                }
                            });
                            if (!valid) {
                                $('#test').attr('style', 'display: block;');
                                // remove invalid value, as it didn't match anything
                                //$( this ).val( "" );
                                //select.val( "" );
                                //input.data( "autocomplete" ).term = "";
                                //return false;                    
                            }
                        }
                    }
                }).addClass("ui-widget ui-widget-content ui-corner-left");
    
                input.data("autocomplete")._renderItem = function(ul, item) {
                    return $("<li></li>").data("item.autocomplete", item).append("<a>" + item.label + "</a>").appendTo(ul);
                };
    
                input.data("autocomplete")._renderMenu = function(ul, items) {
                    var self = this,
                        currentCategory = "";
                    $.each(items, function(index, item) {
                        if (item.category != currentCategory) {
                            if (item.category) {
                                ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
                            }
                            currentCategory = item.category;
                        }
                        self._renderItem(ul, item);
                    });
                };
    
                $("<a>").attr("tabIndex", -1).attr("title", "Show All Items").appendTo(wrapper).button({
                    icons: {
                        primary: "ui-icon-triangle-1-s"
                    },
                    text: false
                }).removeClass("ui-corner-all").addClass("ui-corner-right ui-combobox-toggle").click(function() {
                    // close if already visible
                    if (input.autocomplete("widget").is(":visible")) {
                        input.autocomplete("close");
                        return;
                    }
    
                    // work around a bug (likely same cause as #5265)
                    $(this).blur();
    
                    // pass empty string as value to search for, displaying all results
                    input.autocomplete("search", "");
                    input.focus();
                });
            },
    
            destroy: function() {
                this.wrapper.remove();
                this.element.show();
                $.Widget.prototype.destroy.call(this);
            }
        });
    })(jQuery);
    
    $(function() {
        $("#combobox").combobox();
        $("#toggle").click(function() {
            $("#combobox").toggle();
        });
    });
    

    Example: http://jsfiddle.net/gB32r/

    0 讨论(0)
  • 2020-12-10 04:37

    There is a few features with jquery 10. I take autocomplete combobox from website of jquery ui: http://jqueryui.com/autocomplete/#combobox and join it with Andrew Whitaker answer.

    (function( $ ) {
    $.widget( "custom.combobox_with_optgroup", {
        _create: function() {
            this.wrapper = $( "<span>" )
                .addClass( "custom-combobox" )
                .insertAfter( this.element );
            this.element.hide();
            this._createAutocomplete();
            this._createShowAllButton();
        },
        _createAutocomplete: function() {
            var selected = this.element.find( ":selected" ),
                value = selected.val() ? selected.text() : "";
            this.input = $( "<input>" )
                .appendTo( this.wrapper )
                .val( value )
                .attr( "title", "" )
                .addClass( "custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left" )
                .autocomplete({
                    delay: 0,
                    minLength: 0,
                    source: $.proxy( this, "_source" )
                })
                .tooltip({
                    tooltipClass: "ui-state-highlight"
                });
            this._on( this.input, {
                autocompleteselect: function( event, ui ) {
                    ui.item.option.selected = true;
                    this._trigger( "select", event, {
                        item: ui.item.option
                    });
                },
                autocompletechange: "_removeIfInvalid"
            });
    
            this.input.data("uiAutocomplete")._renderMenu = function(ul, items) {
                var self = this,
                    currentCategory = "";
                $.each(items, function(index, item) {
                    if (item.category != currentCategory) {
                        if (item.category) {
                            ul.append("<li class='custom-autocomplete-category'>" + item.category + "</li>");
                        }
                        currentCategory = item.category;
                    }
                    self._renderItemData(ul, item);
                });
            };
        },
        _createShowAllButton: function() {
            var input = this.input,
                wasOpen = false;
            $( "<a>" )
                .attr( "tabIndex", -1 )
                .attr( "title", "Показать все" )
                .tooltip()
                .appendTo( this.wrapper )
                .button({
                    icons: {
                        primary: "ui-icon-triangle-1-s"
                    },
                    text: false
                })
                .removeClass( "ui-corner-all" )
                .addClass( "custom-combobox-toggle ui-corner-right" )
                .mousedown(function() {
                    wasOpen = input.autocomplete( "widget" ).is( ":visible" );
                })
                .click(function() {
                    input.focus();
    
                    if ( wasOpen ) {
                        return;
                    }
    
                    input.autocomplete( "search", "" );
                });
        },
        _source: function( request, response ) {
            var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
            response( this.element.find( "option" ).map(function() {
                var text = $( this ).text();
                if ( this.value && ( !request.term || matcher.test(text) ) )
                    return {
                        label: text,
                        value: text,
                        option: this,
                        category: $(this).closest("optgroup").attr("label")
                    };
            }) );
        },
        _removeIfInvalid: function( event, ui ) {
    
            if ( ui.item ) {
                return;
            }
    
            var value = this.input.val(),
                valueLowerCase = value.toLowerCase(),
                valid = false;
            this.element.find( "option" ).each(function() {
                if ( $( this ).text().toLowerCase() === valueLowerCase ) {
                    this.selected = valid = true;
                    return false;
                }
            });
    
            if ( valid ) {
                return;
            }
    
            this.input
                .val( "" )
                .attr( "title", value + " не существует" )
                .tooltip( "open" );
            this.element.val( "" );
            this._delay(function() {
                this.input.tooltip( "close" ).attr( "title", "" );
            }, 2500 );
            this.input.data( "ui-autocomplete" ).term = "";
        },
        _destroy: function() {
            this.wrapper.remove();
            this.element.show();
        }
    });
    })( jQuery );
    
    0 讨论(0)
  • 2020-12-10 04:48

    I'am using the jqueryui autocomplete widget on my webapp, with the combobox monkey patching, optgroup (categories) and ability to seach also in category names. The seach term is also emphasized inside compatible option and optgroup. I used several answers from stackoverflow and jqueryui website to get to this point, thanks !

    I like to keep it working on the last version of jqueryui. Jqueryui 1.9 and 1.11 introduced breaking changes (in autocomplete and menu plugin, the lastest being used by the former) and I finally succeeded in making it work with the lastest version of jqueryui (1.11.0) and jquery ( 2.1.1 )

    jsbin here

    Important part : change menu widget options to not consider categories as normal menu link via new items option (so new that not inside the doc but in the jqueryui upgrade guide to 1.11

    $.extend($.ui.menu.prototype.options, {
        items: "> :not(.aureltime-autocomplete-category)"
    });
    
    0 讨论(0)
  • 2020-12-10 04:54

    as you can see in the jQueryUI docs, you have to customize the widget to do that

    _renderMenu: function( ul, items ) {
                var self = this,
                    currentCategory = "";
                $.each( items, function( index, item ) {
                    if ( item.category != currentCategory ) {
                        ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
                        currentCategory = item.category;
                    }
                    self._renderItem( ul, item );
                });
            }
    

    this its not tested, but should be a good start:

    _renderMenu: function( ul, items ) {
                var self = this,
                    currentCategory = "";
                $.each( items, function( index, item ) {
                    if ( item.parent.attr('label') != currentCategory ) {
                        ul.append( "<li class='ui-autocomplete-category'>" + item.parent.attr('label') + "</li>" );
                        currentCategory = item.parent.attr('label');
                    }
                    self._renderItem( ul, item );
                });
            }
    

    if this doesnt work, maybe you should debug to see whats into the items array that comes as a parameter of _renderMenu.

    a side note: this is called MonkeyPatching, i wouldnt recommend doing this a lot, but since the docs show it, id say do it.

    0 讨论(0)
提交回复
热议问题