Super Cool Advanced Lookup Component
Okay, so maybe it isn’t exactly a super cool advanced lookup, but it is a lookup, and it is cool. Title at least got your attention right? No? Darn.
So what is a super cool advanced lookup you may ask? It is basically text field that as you start to type it becomes a picklist of values depending on the text you are typing. You can have it lookup records on any object that has a Name field. This type of functionality can be done with javascript libraries (examples here) but why do that if you can build something that performs just as well using only Apex and Visualforce? I did play around with the ext.js library and it is definitely more polished but on very large data sets performance was not that good. As I would type it felt like it was freezing up. To me this is much more annoying than a slight delay the VF component makes when performing the SOQL query.
Here is the example page, enjoy: http://tehnrd-developer-edition.na7.force.com/comboBox
First we will take a look at the component named advancedLookup. This component has 4 important attributes:
- object: The object you would like to search, Account, Contact, MyCustomObject__c, etc.
- value: This component returns an Id value and this must be bound to a value in your page’s controller or extension
- maxHeight: As you begin you type a picklist will appear of matching results and you must set the default height.
- width: Depending on the object searched the Name may only be 15 characters wide or it could be 250. Here you set the width so the names are readable.
<apex:component controller="advancedLookUp" > <apex:attribute name="object" assignTo="{!objectType}" required="true" type="string" description="The object this component will search."/> <apex:attribute name="value" assignTo="{!selectValue}" required="true" type="object" description="A merge feld that references the controller class variable that is associated with this feld. This must be an Id field."/> <apex:attribute name="maxHeight" assignTo="{!maxHeight}" required="true" type="Integer" description="Max height of selectList."/> <apex:attribute name="width" required="true" type="string" description="Width of the component in pixels or percent."/> <apex:attribute name="style" type="string" description="The style used to display the inputText component, used primarily for adding inline CSS styles."/> <apex:outputPanel layout="block" style="{!style}"> <!-- This is our input text that we will use in a wildcard search against the names of the defined object. We refresh the results every time this field is clicked or a letter is entered (keyup) --> <apex:inputText value="{!searchValue}" style="width:{!width}" id="searchValue"> <apex:actionSupport event="onkeyup" action="{!search}" rerender="resultsPanel"/> <apex:actionSupport event="onclick" action="{!search}" rerender="resultsPanel"/> </apex:InputText> <!-- Once we perform the query on the object we will populate this list with the returned values. When a user selects a value we will hide this list and auto complete the selected value --> <apex:outputPanel id="resultsPanel" layout="block" style="position: absolute;"> <apex:selectList value="{!value}" size="{!height}" style="width:{!width}" rendered="{!showList}" > <apex:selectOptions value="{!results}"/> <apex:actionSupport event="onchange" action="{!selectvalue}" rerender="resultsPanel,searchValue"/> </apex:selectList> </apex:outputPanel> </apex:outputPanel> <!-- This component has one little piece of javascript. If a user clicks on the screen before selecting a value we want to hide the list of options similar to how a normal picklist behaves --> <apex:actionFunction name="hideResults" action="{!hideResults}" reRender="resultsPanel"/> <script type="text/javascript"> document.onclick = function(){ hideResults(); } </script> </apex:component>
Next the controller for this this custom component:
public class advancedLookUp{ public Object selectValue{get; set;} public String objectType {get; set;} public String searchValue {get; set;} public Integer maxHeight {get; set;} public Integer height {get; set;} public List<SelectOption> results {get; set;} public Boolean showList {get; set;} Map<String,String> resultsMap; //This is our seach method that is called every time a character is entered public void search(){ showList = true; results = new List<SelectOption>(); resultsMap = new Map<String,String>(); //Using dynamic SOQL we pass the object and the search value if(searchValue.length() > 0){ String entry = '%' + searchValue + '%'; String queryString = 'Select Id, Name from ' + objectType + ' where Name like :entry order by Name limit 1000'; /*Next we add the results to our list of selectOptions. We also add the values to a map so that when a value is selected we can auto fill the search box with the selected value */ for(sObject o : Database.query(queryString)){ results.add(new SelectOption((String)o.get('Id'),(String)o.get('Name'))); resultsMap.put((String)o.get('Id'),(String)o.get('Name')); } } //Next we inspect the results to set the height and contents of the selectList if(searchValue.length() == 0){ showList = false; }else if(results.size() == 0 && searchValue.length() != 0){ results.add(new SelectOption('','No matches found')); height = 2; }else if(results.size() == 1){ height = 2; }else if(results.size() > maxHeight){ height = maxHeight; }else{ height = results.size(); } } //When a value is selected we will auto complete the searchValue public void selectValue(){ showList = false; searchValue = resultsMap.get((string)selectValue); } //simply hides the list of results public void hideResults(){ showList = false; } }
Almost there now. Up next the page and page controller:
<apex:page controller="coolLookUp"> Try searching with 'e', 'oil', 'az', 'install', etc then click the Show button. <apex:form > <!-- This is only line need for the advanced lookup. The value is bound to an ID variable in this page's controller. When you click the button it refreshes the detail panel and displays the selected opp --> <c:advancedLookup object="Opportunity" value="{!oppId}" maxHeight="20" width="250px" style="float: left"/> <apex:commandButton value="Show" rerender="detail" style="float: left" status="status"/> <apex:actionStatus startText="elevator music...." id="status"/> <apex:outputPanel id="detail"> <apex:detail subject="{!oppId}"/> </apex:outputPanel> </apex:form> </apex:page>
Doesn’t get much more simple than this:
public class coolLookUp { public Id oppId {get; set;} }
FYI, there is an issue if you try to use this component more than once on a page but I have not yet had the time to investigate.

Thanks Jason for this wonderful piece of code. This might help me in the current project I am doing.
This is a killer! Thanks for publishing this good piece of work!
Thanks for such a cool lookup. I have a quick question – You mentioned that “You can have it lookup records on any object that has a Name field.”
I am new to apex and visaulforce and I am wondering if this code can be customized for other field? A custom objects tile field?
This is really nice. I would like to rerender some other parts of the page when the bound value is changed, but not seeing how to do so.
Awesome component, thanks! Have you done any further work on getting two components to work on the same page? I’m running into this issue and haven’t managed to figure out what’s causing it.
Cheers
Sam
Hi:
Love this compenent… How would this work if you have a child object. Basically I have an object Course which has a lookup to Contact. I want to put a field out there which goes off the contact field in Course object??
Otherwise awesome…
One more thing… When I select another Value… and hit Show, the value is not being picked up…
I am basically using your component in a dynamic SOQL reporting design…
Is there a way to refresh the value or something…
I used this code in my custom application.few days worked well. But suddenly stopped working. When I tested in a separate page its working. But as a field in a big form its not at all working