8

Tengo un campo de autocompletar en funcionamiento en mi aplicación web y estoy buscando una forma de aumentar la usabilidad del campo omitiendo automáticamente los campos de categoría cuando una tecla de flecha se usa para desplazarse hacia abajo por las opciones disponibles (después de escribir en un término de búsqueda parcial).

Por ejemplo, si un usuario comienza a escribir "un", el autocompletado mostrará dos categorías con los elementos de cada uno. El usuario desea seleccionar uno de los elementos en la lista debajo de "Personas". Usan la tecla de flecha para moverse hacia abajo en la lista. Actualmente, este código inserta las categorías en los resultados como un elemento de lista. Cuando utilice las teclas de flecha, debe moverlas para pasarlas a fin de resaltar y seleccionar un resultado. De cualquier forma, la aplicación podría omitir automáticamente los encabezados de categoría?Categoría de Autocompletar jQuery UI Cómo saltear encabezados de categoría

$.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); 
     } 
    }); 

Respuesta

5

Esta línea:

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

está causando el problema.

Internally, el widget usa elementos de lista con una clase ui-menu-item para distinguir si un li es o no un elemento de menú real que se puede seleccionar. Cuando presiona la tecla 'hacia abajo', el widget encuentra el siguiente elemento con una clase ui-menu-item y se mueve hacia él.

Retire la clase y el código funciona como usted quiere:

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

Aquí se está trabajando:

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

+0

Perfecto, eso fue mucho más fácil de lo que pensé. Gracias por tu ayuda. – arcdegree

+0

@arcdegree: No hay problema, me alegro de ayudar :) –

+0

Dado que '1.10.4' esto ya no funciona, debido a esto - [Menú: Eliminar el requisito de anclajes en los elementos del menú] (http://bugs.jqueryui.com/ boleto/10130). Esto se debe a que se han eliminado los anclajes, por lo que ya no existe distinción entre los elementos 'li', todos reciben la clase' ui-menu-item' independientemente de si lo especifica o no. – Lankymart

1

Dado que la respuesta aceptada no funciona en las versiones más recientes de jQueryUI (> 1.10.4) Publicaré mi hack, quizás alguien lo encuentre útil.

estoy usando jQueryUI 1.12.0

Si bien añadiendo la categoría añadí nueva clase, lo he llamado "categoryItem":

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

Algunas de las funciones jQueryUI también tienen que ser anulado para forzar jQuery ignorar elementos con la clase "categoryItem" (se cambian dos líneas).

$.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); 
} 
}));