2012-06-14 30 views
12

Estoy usando el combobox de autocompletar de jquery ui, y está funcionando muy bien, pero ahora me estoy volviendo un poco codicioso. Me gustaría poder agregarle categorías. El cuadro combinado se genera de un menú por lo que si he añadido categorías véase el ejemplo debajo de la etiqueta se mostraría como las categorías están en la jquery ui autocomplete categories versionjquery ui autocompletar combobox con categorías

<select> 
<optgroup name="Cat 1">  
<option value="1a">One A</option> 
<option value="1b">One B</option> 
<option value="1c">One C</option> 
</optgroup> 
<optgroup name="Cat 2">  
<option value="2a">Two A</option> 
<option value="2b">Two B</option> 
<option value="2c">Two C</option> 
</optgroup> 
</select> 

creé una http://jsfiddle.net/nH3b6/11/.

Gracias por cualquier ayuda o dirección.

Respuesta

11

Ampliando la sugerencia de @ Jarry, actualizaría su código para determinar a qué optgroup pertenece la opción. A partir de ahí, se puede utilizar código similar al encontrado en el sitio web jQueryUI:

(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(); 
    }); 
}); 

Ejemplo:http://jsfiddle.net/gB32r/

+1

Esto funciona muy bien. Muchas gracias. –

+0

Oye, así que encontré un pequeño error como un subproducto del ajuste que hiciste. Si abro la lista y selecciono una de las opciones de una categoría, aparece "Sin coincidencias". Si selecciono una opción que no está bajo una categoría, funciona muy bien. Traté de resolverlo en vano. –

+0

Nevermind lo descubrió ... select.children ("optgroup"). Children ("option"). Each (function() { –

2

como se puede ver en el jQueryUI docs, tiene que personalizar el widget de hacer eso

_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); 
      }); 
     } 

esto no es probado, pero debe ser un buen comienzo:

_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); 
      }); 
     } 

si ésto no trabajo, tal vez debería depurar para ver cuál es la matriz items que viene como parámetro de _renderMenu.

una nota al margen: esto se llama MonkeyPatching, no recomendaría hacer esto mucho, pero como los documentos lo muestran, id por favor hazlo.

+0

Gracias por la respuesta. Corrígeme si estoy equivocado, pero estás empezando con el código de la versión de "categoría" del autoco mplete Estoy comenzando desde la versión "combobox". Entonces el código de arriba no funcionaría. –

+0

usted no está equivocado. el código es de la categoría. No estoy seguro de si funcionaría, y no puedo probarlo ahora mismo. Creo que funcionará, solo tienes que anular (AKA monkeypatch) la función _renderMenu.Apuesto a que se llama a pesar de que los artículos vienen – Jarry

3

Hay algunas características con jQuery 10. Tomo cuadro combinado autocompletar desde el sitio web de la interfaz de usuario jQuery : http://jqueryui.com/autocomplete/#combobox y únete con la respuesta de Andrew Whitaker.

(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); 
1

I'am utilizando el widget de autocompletar jqueryui en mi aplicación web, con la aplicación de parches cuadro combinado mono, optgroup (categorías) y la capacidad de seach también en títulos de categorías. El término de búsqueda también se enfatiza dentro de la opción compatible y del grupo de selección. Utilicé varias respuestas del sitio web stackoverflow y jqueryui para llegar a este punto, ¡gracias!

Me gusta seguir trabajando en la última versión de jqueryui. Jqueryui 1.9 y 1.11 introdujeron cambios de última hora (en autocompletar y complemento de menú, el último fue utilizado por el anterior) y finalmente tuve éxito en hacerlo funcionar con la última versión de jqueryui (1.11.0) y jquery (2.1.1)

jsbin here

parte importante: widget opciones de menú cambio de no tener en cuenta categorías como enlace del menú normal a través nueva opción de artículos (tan nuevo que no dentro del documento, pero en el jqueryui guía de actualización a 1.11

$.extend($.ui.menu.prototype.options, { 
    items: "> :not(.aureltime-autocomplete-category)" 
}); 
+0

¡Esto es perfecto! Al principio tenía dudas al usar esto, pero esto funcionó y resolvió mi problema, ¡muchas gracias! – NinaNa

Cuestiones relacionadas