Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>With the current combobox implementation, the full list is emptied and re-rendered every time you expand the dropdown. Also you are stuck with setting the minLength to 0, because it has to do an empty search to get the full list.</p> <p>Here is my own implementation extending the autocomplete widget. In my tests it can handle lists of 5000 items pretty smoothly even on IE 7 and 8. It renders the full list just once, and reuses it whenever the dropdown button is clicked. This also removes the dependence of the option minLength = 0. It also works with arrays, and ajax as list source. Also if you have multiple large list, the widget initialization is added to a queue so it can run in the background, and not freeze the browser. </p> <pre><code>&lt;script&gt; (function($){ $.widget( "ui.combobox", $.ui.autocomplete, { options: { /* override default values here */ minLength: 2, /* the argument to pass to ajax to get the complete list */ ajaxGetAll: {get: "all"} }, _create: function(){ if (this.element.is("SELECT")){ this._selectInit(); return; } $.ui.autocomplete.prototype._create.call(this); var input = this.element; input.addClass( "ui-widget ui-widget-content ui-corner-left" ); this.button = $( "&lt;button type='button'&gt;&amp;nbsp;&lt;/button&gt;" ) .attr( "tabIndex", -1 ) .attr( "title", "Show All Items" ) .insertAfter( input ) .button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }) .removeClass( "ui-corner-all" ) .addClass( "ui-corner-right ui-button-icon" ) .click(function(event) { // close if already visible if ( input.combobox( "widget" ).is( ":visible" ) ) { input.combobox( "close" ); return; } // when user clicks the show all button, we display the cached full menu var data = input.data("combobox"); clearTimeout( data.closing ); if (!input.isFullMenu){ data._swapMenu(); input.isFullMenu = true; } /* input/select that are initially hidden (display=none, i.e. second level menus), will not have position cordinates until they are visible. */ input.combobox( "widget" ).css( "display", "block" ) .position($.extend({ of: input }, data.options.position )); input.focus(); data._trigger( "open" ); }); /* to better handle large lists, put in a queue and process sequentially */ $(document).queue(function(){ var data = input.data("combobox"); if ($.isArray(data.options.source)){ $.ui.combobox.prototype._renderFullMenu.call(data, data.options.source); }else if (typeof data.options.source === "string") { $.getJSON(data.options.source, data.options.ajaxGetAll , function(source){ $.ui.combobox.prototype._renderFullMenu.call(data, source); }); }else { $.ui.combobox.prototype._renderFullMenu.call(data, data.source()); } }); }, /* initialize the full list of items, this menu will be reused whenever the user clicks the show all button */ _renderFullMenu: function(source){ var self = this, input = this.element, ul = input.data( "combobox" ).menu.element, lis = []; source = this._normalize(source); input.data( "combobox" ).menuAll = input.data( "combobox" ).menu.element.clone(true).appendTo("body"); for(var i=0; i&lt;source.length; i++){ lis[i] = "&lt;li class=\"ui-menu-item\" role=\"menuitem\"&gt;&lt;a class=\"ui-corner-all\" tabindex=\"-1\"&gt;"+source[i].label+"&lt;/a&gt;&lt;/li&gt;"; } ul.append(lis.join("")); this._resizeMenu(); // setup the rest of the data, and event stuff setTimeout(function(){ self._setupMenuItem.call(self, ul.children("li"), source ); }, 0); input.isFullMenu = true; }, /* incrementally setup the menu items, so the browser can remains responsive when processing thousands of items */ _setupMenuItem: function( items, source ){ var self = this, itemsChunk = items.splice(0, 500), sourceChunk = source.splice(0, 500); for(var i=0; i&lt;itemsChunk.length; i++){ $(itemsChunk[i]) .data( "item.autocomplete", sourceChunk[i]) .mouseenter(function( event ) { self.menu.activate( event, $(this)); }) .mouseleave(function() { self.menu.deactivate(); }); } if (items.length &gt; 0){ setTimeout(function(){ self._setupMenuItem.call(self, items, source ); }, 0); }else { // renderFullMenu for the next combobox. $(document).dequeue(); } }, /* overwrite. make the matching string bold */ _renderItem: function( ul, item ) { var label = item.label.replace( new RegExp( "(?![^&amp;;]+;)(?!&lt;[^&lt;&gt;]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^&lt;&gt;]*&gt;)(?![^&amp;;]+;)", "gi"), "&lt;strong&gt;$1&lt;/strong&gt;" ); return $( "&lt;li&gt;&lt;/li&gt;" ) .data( "item.autocomplete", item ) .append( "&lt;a&gt;" + label + "&lt;/a&gt;" ) .appendTo( ul ); }, /* overwrite. to cleanup additional stuff that was added */ destroy: function() { if (this.element.is("SELECT")){ this.input.remove(); this.element.removeData().show(); return; } // super() $.ui.autocomplete.prototype.destroy.call(this); // clean up new stuff this.element.removeClass( "ui-widget ui-widget-content ui-corner-left" ); this.button.remove(); }, /* overwrite. to swap out and preserve the full menu */ search: function( value, event){ var input = this.element; if (input.isFullMenu){ this._swapMenu(); input.isFullMenu = false; } // super() $.ui.autocomplete.prototype.search.call(this, value, event); }, _change: function( event ){ abc = this; if ( !this.selectedItem ) { var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( this.element.val() ) + "$", "i" ), match = $.grep( this.options.source, function(value) { return matcher.test( value.label ); }); if (match.length){ match[0].option.selected = true; }else { // remove invalid value, as it didn't match anything this.element.val( "" ); if (this.options.selectElement) { this.options.selectElement.val( "" ); } } } // super() $.ui.autocomplete.prototype._change.call(this, event); }, _swapMenu: function(){ var input = this.element, data = input.data("combobox"), tmp = data.menuAll; data.menuAll = data.menu.element.hide(); data.menu.element = tmp; }, /* build the source array from the options of the select element */ _selectInit: function(){ var select = this.element.hide(), selected = select.children( ":selected" ), value = selected.val() ? selected.text() : ""; this.options.source = select.children( "option[value!='']" ).map(function() { return { label: $.trim(this.text), option: this }; }).toArray(); var userSelectCallback = this.options.select; var userSelectedCallback = this.options.selected; this.options.select = function(event, ui){ ui.item.option.selected = true; if (userSelectCallback) userSelectCallback(event, ui); // compatibility with jQuery UI's combobox. if (userSelectedCallback) userSelectedCallback(event, ui); }; this.options.selectElement = select; this.input = $( "&lt;input&gt;" ).insertAfter( select ) .val( value ).combobox(this.options); } } ); })(jQuery); &lt;/script&gt; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload