Salesforce Combobox Autocomplete in IE8 using jQuery
Creating a Combobox Autocomplete Input Field Compatible with Internet Explorer 8+ using jQuery
Issues with Built-in Combobox functionality in Visualforce
If you try to use the off-the-shelf apex tag to using a inputText field to create a combobox by passing in a list of comma-separated values you will get a nasty surprise when you try to open the page in Internet Explorer. Even though IE is officially supported, it will not display correctly.
Apex Default Combobox Tag
<apex:inputtext list="{!getAccounts}" value="{!accountName}"></apex:inputtext>
A great way to get around this limitation is to use the jQuery combo box. The jQuery combo box is not a standard widget and will not be packed into the jQuery UI by default, but you can configure it with a reasonable amount of code.
You will need the following libs:
Avoid conflicts with the Prototype library built into Salesforce
Use this line of code at the top of your visualforce page to avoid conflicts with other javascript libraries. Salesforce uses the Prototype library behind the scenes to implement much of it's functionality. You will need to use j$ instead of $ in all of your jQuery code after using this snippet to avoid conflicts.
Avoid Conflicts with other Javascript Libs
var j$ = jQuery.noConflict();
Configure your Combobox
Then this code will initialize and configure your basic combo box functionality. You can modify various functions and behaviors of the combobox here such as the duration that tooltips display or the names of the css classes applied to your widget.
Configure your jQuery Combobox Widget
(function( $ ) { j$.widget( "custom.combobox", { _create: function() { this.wrapper = $( "<span>" ) .addClass( "custom-combobox" ) .insertAfter( this.element ); this.element.hide(); this._createAutocomplete(); this._createShowAllButton(); }, _createAutocomplete: function() { var selected = this.element.children( ":selected" ), value = selected.val() ? selected.text() : ""; this.input = j$( "<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" }); }, _createShowAllButton: function() { var input = this.input, wasOpen = false; j$( "<a>" ) .attr( "tabIndex", -1 ) .attr( "title", "Show All Items" ) .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(); // Close if already visible if ( wasOpen ) { return; } // Pass empty string as value to search for, displaying all results input.autocomplete( "search", "" ); }); }, _source: function( request, response ) { var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" ); response( this.element.children( "option" ).map(function() { var text = $( this ).text(); if ( this.value && ( !request.term || matcher.test(text) ) ) return { label: text, value: text, option: this }; }) ); }, _removeIfInvalid: function( event, ui ) { // Selected an item, nothing to do if ( ui.item ) { return; } // Search for a match (case-insensitive) var value = this.input.val(), valueLowerCase = value.toLowerCase(), valid = false; this.element.children( "option" ).each(function() { if ( j$( this ).text().toLowerCase() === valueLowerCase ) { this.selected = valid = true; return false; } }); // Found a match, nothing to do if ( valid ) { return; } // Remove invalid value this.input .val( "" ) .attr( "title", value + " Select a value" ) .tooltip( "open" ); this.element.val( "" ); this._delay(function() { this.input.tooltip( "close" ).attr( "title", "" ); }, 900 ); this.input.autocomplete( "instance" ).term = ""; }, _destroy: function() { this.wrapper.remove(); this.element.show(); } }); })( jQuery );
Create a select box
Then you need to create a select dropdown element. This is being accomplished down here using a dynamic apex:selectList while passing in a List of SelectOptions and tracking the value of the selected option using a String from the Apex Controller.
Create your Select box Dropdown using a Dynamic VisualForce selectList Tag
<div class="ui-widget"> <apex:selectList multiselect="false" size="1" title="Select box" value="{!selectBoxValue}" label="Duration" styleClass="largeInput comboboxSelectBox"> <apex:selectOptions value="{!selectBoxList}"/> </apex:selectList> </div>
Add a Variable to Apex Controller
This variable will be in your apex controller to store the value of the selectbox. This String will store the ID of the currently selected value.
Apex Controller Value
public String transactionDateRangeVal {get; set;}
Generate values for your select list
This Apex method in your controller will create the list of values for your select list. You will be returning a List of SelectOption objects back to your select box which will automatically generate the select box from that list which jQuery will convert into a combobox.
Apex Controller method to create a List of SelectOptions
public ListgetSelectBoxList() { List options = new List<selectoption>(); options.add(new SelectOption('Select Value','Select Label')); options.add(new SelectOption('Select Value','Select Label')); return options; }
Initialize your combobox
Initialize your combobox by using a unique class name in the apex:selectList. The class name comboboxSelectBox is used in this case. Why can't you use the id parameter? Because Salesforce uses the id parameter to create a dynamic id that it uses for it's built in functionality. You won't have access to it unless you override the value using javascript but that would break existing functionality native to Salesforce.
Initialize your SelectBox into a jQuery Combobox
j$(function() { j$( ".comboboxSelectBox" ).combobox(); j$( "#toggle" ).click(function() { j$( ".comboboxSelectBox" ).toggle(); }); });
Match the default Salesforce Look and Feel
Here is some CSS to override the default jQuery style and make it fit in with the look-and-feel of Salesforce. Off-the-shelf jQuery UI elements will clash pretty heavility with Salesforce UI elements so I highly recommend you use this code and modify it further to reach a more unified user experience.
CSS to help the jQuery Combobox look more like the Salesforce default Look and Feel
ul.ui-autocomplete { overflow: auto; max-height: 300px; } .custom-combobox { position: relative; display: inline-block; } .custom-combobox-toggle { position: absolute; top: 0; bottom: 0; margin-left: -1px; padding: 0; /* support: IE7 */ *height: 1.4em; *top: 0.1em; } .custom-combobox-input { margin: 0; padding: 0.2em; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { background: white; border: 1px solid gray; } .ui-widget { font-family: Arial,Helvetica,sans-serif; color: #000; font-size: 1.023em; } input.ui-state-default, input.ui-widget-content input.ui-state-default, input.ui-widget-header input.ui-state-default { width: 177px; } a.ui-state-default, a.ui-widget-content a.ui-state-default, a.ui-widget-header a.ui-state-default { width: 20px; border-left: 0px solid gray; border-right: 1px solid gray; border-top: 1px solid gray; border-bottom: 1px solid gray; } .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { border-bottom-right-radius: 0px; } .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { border-bottom-left-radius: 0px; } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { border-top-right-radius: 0px; } .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { border-top-left-radius: 0px; }
Comments
Post a Comment