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:
  • jQuery javascript library - jQuery
  • jQuery UI javascript library - jQuery UI



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 List getSelectBoxList() {
        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;
}    
Software Development Blogs - BlogCatalog Blog Directory

Popular posts from this blog

How to set up a SQL Server 2008 Local Database

Spring Boot Internationalization with Default Locale for Message Strings

Change Port on a Spring Boot Application when using intelliJ