【问题标题】:jQuery UI Autocomplete Category How to Skip Category HeadersjQuery UI 自动完成类别如何跳过类别标题
【发布时间】:2011-09-05 15:30:16
【问题描述】:

我的 Web 应用程序中有一个可用的自动完成字段,我正在寻找一种方法来提高该字段的可用性,方法是在使用箭头键向下滚动可用选项时以某种方式自动跳过类别字段(输入部分搜索词后)。

例如,如果用户开始输入“an”,自动完成将显示两个类别,每个类别中都有项目。用户想要在“人员”下的列表中选择一项。他们使用箭头键向下移动列表。目前,此代码将结果中的类别作为列表项插入。使用箭头键时,您必须移动经过它们才能突出显示并选择结果。应用程序可以通过什么方式自动跳过这些类别标题?

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

    var data = [
        { label: "annk K12", category: "Products" },
        { label: "annttop C13", category: "Products" },
        { label: "anders andersson", category: "People" },
        { label: "andreas andersson", category: "People" },
        { label: "andreas johnson", category: "People" }
    ];

    $( "#textfield" ).catcomplete({
        source: data,
        select: function(event, ui) {
            window.location.hash = "id_"+escape(ui.item.id);
        }
    });

【问题讨论】:

    标签: jquery-ui autocomplete jquery-ui-autocomplete categories


    【解决方案1】:

    这一行:

    ul.append( "<li class='ui-menu-item ui-category'>" + item.category + "</li>" );
    

    导致问题。

    Internally,小部件使用类ui-menu-item 的列表项来区分li 是否是可以选择的实际菜单项。当您按下“向下”键时,小部件会找到具有 ui-menu-item 类的下一个项目并移动到它。

    删除该类,您的代码将按照您的意愿运行:

    ul.append( "<li class='ui-category'>" + item.category + "</li>" );
    

    它正在工作:

    http://jsfiddle.net/andrewwhitaker/pkFCF/

    【讨论】:

    • 完美,这比我想象的要容易得多。感谢您的帮助。
    • @arcdegree:没问题,很高兴为您提供帮助:)
    • 由于 1.10.4 这不再有效,由于这个 - Menu: Remove requirement for anchors in menu items。这是因为锚点已被移除,因此 li 元素之间不再有任何区别,无论您是否指定,都将获得 ui-menu-item 类。
    【解决方案2】:

    由于接受的答案在最新版本的 jQueryUI (>1.10.4) 中不起作用,我将发布我的 hack,也许有人会觉得它有用。

    我正在使用 jQueryUI 1.12.0

    在添加类别时,我添加了新类,我将其称为“categoryItem”:

    ul.append( "<li class='ui-autocomplete-category categoryItem'>" + "Category" + "</li>" );
    

    还需要重写一些 jQueryUI 函数以强制 jquery 忽略具有“categoryItem”类的项目(更改了两行)。

    $.widget("ui.menu", $.extend({}, $.ui.menu.prototype, {
      refresh: function() {
        var menus, items, newSubmenus, newItems, newWrappers,
            that = this,
            icon = this.options.icons.submenu,
            submenus = this.element.find( this.options.menus );
    
        this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
        // Initialize nested menus
        newSubmenus = submenus.filter( ":not(.ui-menu)" )
            .hide()
            .attr( {
                role: this.options.role,
                "aria-hidden": "true",
                "aria-expanded": "false"
            } )
            .each( function() {
                var menu = $( this ),
                    item = menu.prev(),
                    submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
    
                that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
                item
                    .attr( "aria-haspopup", "true" )
                    .prepend( submenuCaret );
                menu.attr( "aria-labelledby", item.attr( "id" ) );
            } );
    
        this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
    
        menus = submenus.add( this.element );
        items = menus.find( this.options.items );
    
        // Initialize menu-items containing spaces and/or dashes only as dividers
        items.not( ".ui-menu-item" ).each( function() {
            var item = $( this );
            if ( that._isDivider( item ) ) {
                that._addClass( item, "ui-menu-divider", "ui-widget-content" );
            }
        } );
    
        // Don't refresh list items that are already adapted
        newItems = items.not( ".ui-menu-item, .ui-menu-divider" ).not(".categoryItem");
        newWrappers = newItems.children()
            .not( ".ui-menu" )
                .uniqueId()
                .attr( {
                    tabIndex: -1,
                    role: this._itemRole()
                } );
        this._addClass( newItems, "ui-menu-item" )
            ._addClass( newWrappers, "ui-menu-item-wrapper" );
    
        // Add aria-disabled attribute to any disabled menu item
        items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
    
        // If the active item has been removed, blur the menu
        if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
            this.blur();
        }
    
    },
        _move: function( direction, filter, event ) {
        var next;
        if ( this.active ) {
            if ( direction === "first" || direction === "last" ) {
                next = this.active
                    [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
                    .eq( -1 );
            } else {
                next = this.active
                    [ direction + "All" ]( ".ui-menu-item" )
                    .eq( 0 );
            }
        }
        if ( !next || !next.length || !this.active ) {
            next = this.activeMenu.find( this.options.items ).not(".categoryItem")[ filter ]();
        }
    
        this.focus( event, next );
    }
    }));
    

    【讨论】:

      【解决方案3】:

      对于那些最终在这里尝试让类别在 jQueryUI 1.12 中正常工作的其他人...

      bakus33's answer 有效,但我不喜欢扩展小部件(也许我太挑剔了)并找到了更本地化的方式。

      在自动完成选项的created 处理程序中添加以下内容:

      $(this).data('uiAutocomplete').menu.options.items = '> *:not(.class-of-items-to-exclude)';
      

      例如

      $("#searchBox").autocomplete({
            create: function () {
                  //access to jQuery Autocomplete widget differs depending
                  //on jQuery UI version - you can also try .data('autocomplete')
                  $(this).data('uiAutocomplete')._renderMenu = function (ul, items) {
                        var self = this;
                        var categoryArr = [];
      
                        function contain(item, array) {
                              var contains = false;
                              $.each(array, function (index, value) {
                                    if (item === value) {
                                          contains = true;
                                          return false;
                                    }
                              });
                              return contains;
                        }
      
                        $.each(items, function (index, item) {
                              if (!contain(item.category, categoryArr)) {
                                    categoryArr.push(item.category);
                              }
                        });
      
                        $.each(categoryArr, function (index, category) {
                              ul.append("<li class='ui-autocomplete-group category-item'>" + category + "</li>");
                              $.each(items, function (index, item) {
                                    if (item.category === category) {
                                          self._renderItemData(ul, item);
                                    }
                              });
                        });
                  };
                  
                  // Tell the menu to ignore '.category-item' items.
                  $(this).data('uiAutocomplete').menu.options.items = '> *:not(.category-item)';
                  
            },
      });
      

      公平警告,这可能会有其他副作用,但似乎对我有用。您可能还想检查 menu.options.items 的值对您来说是什么,并将 :not() 应用到该值

      【讨论】:

        猜你喜欢
        • 2011-12-15
        • 2012-11-10
        • 2011-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-06
        相关资源
        最近更新 更多