Tweet |
This blog entry shows how to create your own visualforce lookup page backed by a custom controller that gives you full control.
My basic page for demonstrating custom lookup functionality is shown below:
The Lookup link pops up the lookup window. Search text is entered into the input field and clicking the Go button returns the results into the results section:
Clicking the name populates the lookup text field on the main page, and to prove that it is working, clicking the Get Contacts button retrieves the contacts associated with the account:
The first point to mention regarding lookups is that there are actually two fields that are filled in on the target page when you select a lookup result. The name of the selected item is displayed in the visible field, but names are not unique so this is not enough information to uniquely identify the chosen item. Thus there is a hidden field that captures the the ID of the selected record.
Below is a snippet of a VisualForce page that contains my custom lookup combination field. For the sake of simplicity I've chosen to use a clickable link to launch the lookup dialog.
<apex:pageBlock title="Lookup"> <apex:pageBlockSection columns="1"> <apex:pageBlockSectionitem > <apex:outputLabel value="Account"/> <apex:outputPanel > <apex:inputHidden value="{!accountId}" id="targetId" /> <apex:inputText size="40" value="{!accountName}" id="targetName" onFocus="this.blur()" disabled="false"/> <a href="#" onclick="openLookupPopup('{!$Component.targetName}', '{!$Component.targetId}'); return false">Lookup</a> </apex:outputPanel> </apex:pageBlockSectionitem> </apex:pageBlockSection> <apex:pageBlockSection > <apex:pageBlockSectionitem > <apex:commandButton value="Get Contacts" action="{!findContacts}"/> </apex:pageBlockSectionitem> </apex:pageBlockSection> </apex:pageBlock>
Digging into the markup, we can see that as well as the text field and link, the hidden field to capture the link is also present. When the user clicks the link, the following javascript is executed to open the popup. Note that the HTML element ids are passed as parameters to the popup page - this allows the popup to locate the fields to populate when the user makes a selection. Note also that the javascript function to close the popup window is located in the main page, not the popup page. This is required as browsers often only allow a window to be closed by the same page that opened it.
<script> var newWin=null; function openLookupPopup(name, id) { var url="/apex/LookupExamplePopup?namefield=" + name + "&idfield=" + id; newWin=window.open(url, 'Popup','height=500,width=600,left=100,top=100,resizable=no,scrollbars=yes,toolbar=no,status=no'); if (window.focus) { newWin.focus(); } return false; } function closeLookupPopup() { if (null!=newWin) { newWin.close(); } } </script>
Now we move on to the popup VisualForce page. This consists of a criteria section and a results table. Clicking the Go button invokes a controller action method that executes a SOSL query to retrieve all accounts matching the input string. The VisualForce markup for the results table is shown below.
<apex:pageBlock > <apex:pageBlockSection columns="1"> <apex:pageBlockTable value="{!accounts}" var="account"> <apex:column headerValue="Name"> <apex:outputLink value="#" onclick="fillIn('{!account.Name}', '{!account.id}')">{!account.Name}</apex:outputLink> </apex:column> <apex:column headerValue="Street" value="{!account.BillingStreet}"/> <apex:column headerValue="City" value="{!account.BillingCity}"/> <apex:column headerValue="Postcode" value="{!account.BillingPostalCode}"/> </apex:pageBlockTable> </apex:pageBlockSection> </apex:pageBlock>
As you can see, the account name column is actually a link that invokes a JavaScript function shown below:
function fillIn(name, id) { var winMain=window.opener; if (null==winMain) { winMain=window.parent.opener; } var ele=winMain.document.getElementById('{!$CurrentPage.parameters.namefield}'); ele.value=name; ele=winMain.document.getElementById('{!$CurrentPage.parameters.idfield}'); ele.value=id; CloseWindow(); } function CloseWindow() { var winMain=window.opener; if (null==winMain) { winMain=window.parent.opener; } winMain.closeLookupPopup(); }
This JavaScript is the glue between the two pages - it fills in the HTML elements in the main page and closes the popup window.
The pages and controllers can be downloaded here. Simply unzip into the src directory of your Force.com project in the IDE.
Nice effort, I would suggest using HTML z-index to overlay a div, like jquery colorbox etc to achieve this.
ReplyDeleteNice, thanks for the information. I am new to the technology searching for what can do & how can do with components of visualforce.
ReplyDelete@Abhinav - yes, layering is the next logical step. It would remove some javascript for focus grabbing and window closing. As always, time is the limiting factor ;)
ReplyDeleteCan you use something like this on a sites page and have a lookup filter? The application is this: An user (role = product distributor) logs into a VF sites page, they are registering a deal (which goes into SFDC as a lead) and need to connect a partner account, which is a reseller that uses that distributor, (which is a lookup field on the lead) to the lead. Basically, the distributor is registering the deal on behalf of the reseller.
ReplyDeleteI want the distributor to only have access to look up reseller accounts that are linked to his account.
Would this solution be a starting point for that type of solution?
Thanks
joannculbertson@gmail.com
@JoAnn - I guess it could be used as a starting point for that. The controller would need some work to pull back the logged in user's information and apply a filter to the query. That said, it looks more like a partner portal use case to me - is there any reason why you wouldn't go that route?
ReplyDeleteThanks for the post and source!
ReplyDeleteThis is a nice little example that can be extended. I am using it as a simple starting point and extending it and its working nicely.
I like that it creates a popup similar to standard SF Lookup functionality. Its transparent to user that this is VF page as it behave just like SF lookup on standard edit pages.
Thanks!
Bob,
ReplyDeleteIm trying your code in eclipse force IDE. It works on its own, but when I try to integrate it into my own visualforce page, I get this error:
"Description Resource Path Location Type
Save error: Unknown constructor 'LookupMainController.LookupMainController(ClaimAndRequest controller)' ClaimAndRequest.page /AtsMemberUpdate/src/pages line 0 Force.com save problem
"
Any idea what this means?
This usually means that you have declared LookupMainController as an extension to to the standard controller for ClaimAndRequest objects. An extension controller must provide a constructor that takes the standard controller as a parameter.
ReplyDeleteA nice solution in keeping with Salesforce behaviour. If only Salesforce would allow you to pass filter arguments to lookups ...
ReplyDeleteHi Bob:
ReplyDeleteNice example. In your LookupExampleMain.page, this is a custom Visualforce page. If you wanted to "glue" the custom loookup and populate a field on a "stock" salesforce page, would your example work in this case?
Any hints, pointers here in achieving this?
thx.
W. MacKenzie
Unfortunately this only works for a custom page, as the standard lookup icon doesn't allow you to control what happens when it is clicked.
ReplyDeleteUnderstood. I created a customer VF page to try it out using your example. I hooked it up to invoke my VF page controller/page setup to perform the lookup.
DeleteIt doesn't appear however to be passing the args (targetName and targetId) to the VisualForce page.
What should the url look like that is being assembled?
got it. I was attempting to return values in the fillin method with values which were not yet completed. I was expecting the action method on the inputText to fire before onclick but it wasn't. Replaced onclick with oncomplete and it fixed it.
Deletei used this logic in pageblock table column and its working fine. The requirement is to open the popup inline..I used the " Css display :inline" but what is happening is when i click on any of the values in column it opens the pop up inline to the first row only.. Could you please help me out. Its on an urgent basis..
ReplyDeleteI would be good if u give me ur mail id.. I will share my code with u
I can't provid 1-1 help I'm afraid. Best I can suggest is to post your code up to the developerforce visualforce discussion board.
DeleteI want to add 'X' next to the lookup icon which clears the input field value. After the field gets populated, later when I open the visualforce page, the field is prepopulated with that value. When I click X, the input field should be nulled. How is it possible?
ReplyDeleteWow....its very similar to standard functionality lookup of salesforce .
ReplyDeleteHi bob,
ReplyDeleteIf there is possible to call the visualfore page from the default layout of th object. i.e my requirement is i want to call the poopup page from the standard page lookup field instead of main page.
My requirement is simular. They want to replace the lookup field with a visualforce page. I have built the visulforce page and got it to search. But now am stuck on replacing the field. I am rebuilding the standard page into a visual force page to do this. I am trying to use an extension for my popup controller but am lost. Such a newbie it is sad..
Deletethis is an original article by Jeff Douglas... please provide appropriate credits...
ReplyDeleteExcept that Jeff wrote his post on August 12th 2011, while I wrote mine on 25th September 2010 - quite impressive of me to use his post nearly a year before he'd written it.
DeleteBelieve it or not, its possible to two people to write a blog post on the same topic independently.
Yes Bob ! I did realize that later and your 100% right about ur work being original. Also its possible for two people to write a blog post the same but the reason I pointed out was the code snippet was exactly the same :-) I will right away post on Jeff's blog to provide you the credits !
DeleteYes Bob ! I did realize that later and your 100% right about ur work being original. Also its possible for two people to write a blog post the same but the reason I pointed out was the code snippet was exactly the same :-) I will right away post on Jeff's blog to provide you the credits !
ReplyDeleteWorks perfectly, Thanks! Combined with <img src="/s.gif" alt="Location Name Lookup (New Window)" .... to give me the hourglass icon
ReplyDeletewhen i try to use it gives an error as accountid is not a property
ReplyDeleteAccountid is a property in the main lookup controller that is downloaded from the link - have you downloaded all of the source?
DeleteHi Bob, I've been trying to figure out how to pass the value of the input text name to the OpenLookupPopup with no luck. It works great without it, but I know my users will attempt to enter text then click the search button. Seems the value of the text is not set at the time the pop up is called. Your wizardry is much appreciated. Thanks!
ReplyDeleteYou'll need to pull the value of the underlying HTML element and pass that through as an additional parameter to the popup URL, then get the popup controller to execute a search if the parameter has a value.
DeleteThank you for your post. I used some of this code to help me build something slightly different. I got the visual page to run. Yeah!
ReplyDeleteThank you so much for your post! It's very useful!
ReplyDeleteHi Bob,
ReplyDeleteYour post is quite impressive. I have a li'l similar requirement to this. In a visualforce page I have to display Account lookup. But when user don't find the record he is looking for, I need to capture the text entered by him in that field and create an Account from the controller. Is it possible to click a button by just entering a text in the lookup field even if no record exist matching with the text entered? Please guide me. TIA.
Hi Bob,
ReplyDeleteThank You for the Post. I have similar requirement where I have 2 lookups and based on first lookup value i need to go and retrieve the 2nd lookup values. Please let me know your thoughts how to achieve it.
Thank You
This one really helped me a lot one year ago... :) Nice post bingo..!!!!!
ReplyDeleteHi Bob,
ReplyDeleteThank you for the Post. Really helped me a lot.
But currently i am facing an issue with look-up. The look-up data is getting cleared in page where as the data is getting successfully saved in database. Can you please help me out.
Thank You.
Thanks for the Information Bob.....
ReplyDeleteIt helped to complete my task....
Hello Bob,
ReplyDeleteOnce account name is populated in main page, I want to go and fetch some more fields from account object and show them in the same age. I tried action support , but it is not firing onchange event. do you have any suggestion.
@Bob, is there a way to tie up the lookup with inputText directly. I don't use standard ID field to search records but will use the custom 'text' input.
ReplyDeleteHi Bob,
ReplyDeleteThis page is not working for me in public sites. When click on lookup link the popup is coming but page is showing under construction. I have given page,class and obj access. please let me know how to solve this issue.
Thanks,
Lakshmi
Hello,
ReplyDeleteIt worked fine, but I have a little problem.
When I check the value that is being sent in: !$Component.targetName} I don't get a value but something like a reference j_id0:j_id2:targetName.
Do you know what can I be doing wrong?
Thanks!
Do you have test class?
ReplyDeleteHi Bob, This is really helpful post. Is similar kind of solution possible with custom Select Template button in VF Page? I have created custom button in in VF Page and when I click on that button it should open TemplateSelector page and after selecting template it should pass template to parent page (VF Page).
ReplyDeleteAny workaround to it?
Hi Bob,
ReplyDeleteI have used the code you have provided and used it. When I search the lookup field without giving any input (keep the lookup field blank and click on Go) It returns the error of runQuery().
Please assist.
Hi Bob or anyone who can help.
ReplyDeleteI cannot figure out why, on the Initial page to enter the account name, the inputfield is not enabled. I cannot type into it. Any help would be awesome...
This is intentional. I didn't put in anything to allow you to type into the lookup and retrieve the associated id, so I added a handler to stop focus on the input field.
DeleteI resolved! Thank you
ReplyDeleteMy lookup page just displays the headings? Any help would be great.
ReplyDelete{!account.Name}
I tried to post the page. Was not able.
ReplyDeleteIf you are having problems post to the Salesforce developer forums - I will likely see it, but so will loads of other developers who can help you.
DeleteThat was a great example. Do you have an example of entering First and Last Name on the page. Pressing lookup passes both values to a popup window, which lists the passed values as headings and lists the Accounts in a table based on the 2 passed values? Window does not return anything.
ReplyDeleteit's not working for special character's like
ReplyDeleteContact requestors to correct mistakes on OR's
Hi Bob, Where are you passing idfield and namefield?
ReplyDeleteHi Bob,
ReplyDeleteWhere are you instantiating namefield and idfield?
You Are Great
ReplyDeletePopup button gets disappear in lightning.... it only works in classic. Can anybody tell the solution?
ReplyDeleteGreetings Bob Buzzard,
ReplyDeleteI know that this post is "old" but GOLD! I am here to thank you for this tutorial! In fact, I am a trailblazer who started out fresh in doing Salesforce Programming.
I was looking for this kind of solution because I would want to avoid the governor limits on SelectOption which is 1,000 records. But nevertheless, Thank you once again!
By-the-way, I modified your code that renders the "Lookup" text into a "Lookup Icon;" so that, it would REALLY LOOK LIKE a "Lookup" field xD.
Hi, pls how did you get the lookup icon?
Delete