You need to sign in to do that
Don't have an account?

Creating a Visualforce Popup window that operates similar to the Lookup popup windows
I'm starting to do some research into what it would take to create a Visualforce popup window similar to the standard salesforce lookup windows. For now, my intention is to try to come up with a stronger lookup window for one of our custom objects, and at the moment I plant to create a link on a visualforce page to bring the popup up. (This link will be right next to the existing standard salesforce lookup icon.)
I figured I'd start by seeing if anyone else has had any success doing something like this. The items I am going to tackle first are:
1. Create the popup window. - Don't expect this to be a problem.
2. Pass parameters to the popup through the URL - Don't expect this to be a problem.
3. Emulate the existing functionality of an existing Salesforce lookup, so that the lookup window will disappear automatically if the parent window is reselected - Not sure how to implement this one yet
4. Pass a value, in this case, an Id back to the parent window - Not sure how I'm going to do this, but I'm going to attempt to pass some sort of callback function into the popup so it can return a value
Being able to do something like this leads to the need to be able to override standard Salesforce lookup functionality. That way this could be easily implemented on standard pages, in addition to VisualForce pages.
If anyone has attempted something like this with Visualforce yet, any learnings would be great!
Thanks!
Jon Keener
Can you describe what it is about your lookup interface that is different?
We are considering designs for type-specific inputField elements and your input would be tremendously helpful.
Thanks,
2. Default the search to a "LIKE" vs. "starts with"
3. Search across multiple fields
4. Add some basic filters
5. Include a drop down (similar to whats in print preview right now) to allow the user some flexibility on the number of results returned
6. It might be interesting to have a "recent items" list on the lookup pages for each specific object (This one is probably better for ideas, because I don't think I'd try to implement this one myself...)
Overall, that's a quick synopsis of the kinds of things I would be trying to tackle on a custom lookup. I think functionality-wise, the items above should be pretty doable (some generically/re-usable, some not) in Visualforce/APEX. The tougher part to me is the whole pop-up functionality, and whether that part is doable, hence my previous post.
Of course, I've love to see all of this put into standard Salesforce. I'm sure there's ideas in ideas.salesforce.com for most of these. I'm just curious of what might or might not be possible with popups in Visualforce, because it could lead to some interesting things beyond lookups.
Jon Keener
"It's extremely limiting on Custom Objects to only search the name field, especially when in the results they see a lot more fields that they would like to search on"
At first, it was hard to realise that the lookup window is badly limited what comes for searching.
One example from my organisation:
- We have custom object "Resource" with following fields:
Resource ID: autonumber RES-{0}
Resource firstname: Text
Resource lastname: Text
External resource: Checkbox
- If i want to find resource "John Doe", I need to know John's autonumerated value RES-123
- I cannot search using lastname field although that would be the best choice for limiting search results.
Message Edited by Legetz on 01-19-2009 01:18 AM
The harderst part is to pass the value/id back to the parent window.
It can be done using javascript. And you can reuse the function that SFDC is using for there lookup page
It's lookupPick() located in functions.js
View the page source of saleforce lookup page will give you some ideas of how to use this function
Hey there,
I am trying to achieve something similar. Can you please give me more pointers on it?
Thanks much!
Regards
Mukul
I think I would implement this as two visualforce pages (or, you could be sneaky and make it just one, but we'll keep it simple).
To implement a custom lookup window, you'd have to do the following:
1) Use window.open to open a new window.
2) You can pass paramters via tha url and grab them in the recipient frame using ApexPages.currentPage().getParameters().get('param') syntax.
3) Set a "window.onfocus" handler in the parent window. Have the callback for this function close the frame window if it's open.
4) A function in the parent window can be created with one parameter, a string value. The popup window can call window.opener.someFunction(value) to pass the value back to the parent frame. someFunction can also close the popup window (much like in #3). An alternative method would be to set a window.onblur method in the popup, and that could cause it to close if it loses focus for any reason at all.
While I'm entirely too non-energetic to actually write a working example tonight, I know it can be done. I wrote a custom list button once that allowed you to reassign opportunity owners using the standard lookup functionality. Actually, I still have that code... I'll post it here. I apologize for its programming style, it's not exactly what I described, but that's only because it uses the standard Salesforce lookup window, so I had to be accomodating (amazingly, I wrote this in Winter '08 and it still works).
{!RequireScript("/js/functions.js")} var recordsToTransfer = {!GetRecordIds($ObjectType.Opportunity)} function createForm() { form = document.createElement('form') form.name = 'lookupform' form.id = 'lookupform' document.body.appendChild(form) } function addElement(name,value) { form = document.getElementById('lookupform') element = document.createElement('input') element.name = name element.id = name element.type = 'hidden' element.value = value form.appendChild(element) } function doAction() { window.removeEvent(window,'focus',doAction,true) userToTransferTo = document.getElementById('lookup_lkid').value if(userToTransferTo == '') return recordArray = new Array() for(recordToTransfer in recordsToTransfer) { var Opportunity = new sforce.SObject("Opportunity") Opportunity["Id"] = recordsToTransfer[recordToTransfer] Opportunity["OwnerId"] = userToTransferTo recordArray.push(Opportunity) } try { results = sforce.connection.update(recordArray) } catch(e) { alert(e) } window.top.location.href = window.top.location.href } function setupTransfer() { if(recordsToTransfer.length < 1) { alert('Please select at least one row!') return } if(!document.elementsAddedToPage) { createForm() addElement('lookup_lkid','') addElement('lookup_lkold','') addElement('lookup_lktp','005') addElement('lookup_lspf','0') addElement('lookup_mod','0') addElement('lookup','') document.elementsAddedToPage = true } openLookup( '/_ui/common/data/LookupPage?lknm=lookup'+ '&lkfm=lookupform&lkrf=&sn=1&lktp='+ document.getElementById('lookup_lktp').value, 670, document.getElementById('lookup_mod').value, '&lksrch='+ escapeUTF(document.getElementById('lookup').value), 'maxw') window.addEvent(window,'focus',doAction,true) } setupTransfer()
As always, never know wheninteral APIs will change, so don't use thiscode verbatim in a system you care about (i.e. production). However, it should serve as a nice example for the basis of a lookup window. If you have any questions about it, feel free to send me a private message.
Hi sfdcfox,
Thanks for the reply.. I tried doing that but i am stuck at one point. I dont know how to get the checkbox values and pass it back to the parent form:
Here is the snippet that calls the child window:
<apex:column > <span id="filter_lookup0" style="{!showFilter}"><img src="/s.gif" alt="Lookup (New Window)" onClick="javascript:window.open('/apex/lookUpWindow?lookup={!fieldName}', 'lookupwindow', 'height=500, width=700,resize=0')" title="Lookup (New Window)"/></span> </apex:column>
Here is my Visual force page code for the lookup window:
<apex:page controller="newScoreRuleController"><apex:form id="lookup"><apex:pageBlock ><apex:dataTable value="{!lookupList}" var="leadOutput" styleClass="tableClass list" rowClasses="odd,even"> <apex:column ><apex:facet name="header">Value</apex:facet><apex:outputText value="{!leadOutput.Industry}" id="valLookup"/></apex:column><apex:column ><apex:facet name="header">Select</apex:facet><apex:inputCheckBox value="{!leadOutput.Industry}" id="selectedLookUpVal"/></apex:column></apex:dataTable><apex:pageBlockButtons ><script type="text/javascript">function insertSelectedRecords() { var e= document.getElementById('{!$Component.lookup}').elements.length; var cnt=0; var reg = new RegExp('selectedLookUpVal'); for(cnt=0;cnt<e;cnt++) { if(reg.test(document.getElementById('{!$Component.lookup}').elements[cnt].name)){ //alert('here'); if (document.getElementById('{!$Component.lookup}').elements[cnt].checked) { // Get the value in a string and return it to the parent window....(??) alert(document.getElementById('{!$Component.lookup}').elements[cnt].value); //alert(document.getElementById('{!$Component.valLookup}').value); } } }// var inserteddata = document.getElementById('{!$Component.selectedLookUpVal}').checked;}</script><apex:commandButton value="Insert Selected" onClick="javascript:insertSelectedRecords();"/></apex:pageBlockButtons></apex:pageBlock></apex:form></apex:page>
here is my controller code:
public List<Lead> getLookUpList() {String lookupParam = ApexPages.currentPage().getParameters().get('lookup'));String Qry = 'select ' + lookupParam + ' from lead where ' + lookupParam + ' != null';List<Lead> P = Database.Query(Qry); return P; }
Please help!!!
Regards
Mukul
To include custom fields into a search you can make them External Ids. This setting on the field definition will add the field into the sidebar search (and presumably the lookup searches as well as Advanced Search). You can only have 3 custom fields in an object with this setting as it indexes the table but it's helpful when you are using the autonumber type of object name and want to look up items in your case by resource firstname or resource lastname
Niki
Has anyone been able to accomplish this task?
How do we pass the selected value back to the parent form.
I used the link below to learn how to build this. The build was easy and the code is easily adaptable for more sophistication. For 1 I Initialized the search string as it's stupid for it to default that of the current record requiring the user to clear it and press go. Likewise, I intend the expand the search logic as well.
I still have 2 issues:
1. I used field sets as suggested but the page for NEW is empty except for Tilte & Save button.
I there another set to acess field sets after defining them?
2. I don't see how to associate it and override the standard lookup inherited with the Object of my page.
Any ideas. I hope this works for some of you.
http://blog.jeffdouglas.com/2011/08/12/roll-your-own-salesforce-lookup-popup-window/
Hi notsosmart, I'm actually trying to get that code from Jeff's blog to work. I am struggling due to limited ability to even get it to run mimicking the example. No chance you could help out is there?
I can see what the code set is doing BUT the thing I cannot see is how on earth that jQuery knows how to intercept the click. I can't see what I have to edit (considering I am trying to do the same code as Jeff) to make it work. At the moment, nothing different happens on click.
public with sharing class AssignNewAccountToContact
{
public Contact c {get;set;}
public String selectedAccountName {get;set;}
public String selectedAccountId {get;set;}
public AssignNewAccountToContact()
{
selectedAccountName = '';
selectedAccountId = '';
c = [select id, name from Contact where id = :ApexPages.currentPage().getParameters().get('id')];
System.debug('////////////c is ' + c);
}
public pageReference changeTheAccount()
{
System.debug('//////////selectedAccountId is ' + selectedAccountId);
System.debug('//////////selectedAccountName is ' + selectedAccountName);
if(selectedAccountId != '')
{
System.debug('//////////selectedAccountId is not null, so proceeding ');
c.accountId = selectedAccountId;
update c;
ApexPages.addMessage(new ApexPages.message(ApexPages.severity.info, 'New account assigned successfully'));
/*
Make variables null, so that if something is typed now in the textbox,
it gives error message if "Assign new account" is clicked again.
*/
selectedAccountId = '';
selectedAccountName = '';
}
else
{
System.debug('//////////selectedAccountId is null');
ApexPages.addMessage(new ApexPages.message(ApexPages.severity.error, 'Kindly select an account by clicking on Lookup'));
}
return null;
}
}
<!--
VF page name :- vfAssignNewAccountToContact
Main VF page for assigning new account to a contact. Go to an existing contact record and add
/apex/vfAssignNewAccountToContact?id=<ContactRecordID> to the URL to view this VF page.
-->
<apex:page controller="AssignNewAccountToContact">
<apex:form >
<apex:PageMessages id="messages"/>
Click on Lookup to select a new account for this contact and then click on "Assign new account"
<apex:pageBlock title="Contact Details">
Contact name: {!c.name}
<br/>
<apex:pageBlockSection>
<apex:inputText value="{!selectedAccountName}" id="accountName" label="Account"/>
<a onclick="popUp();" style="cursor: pointer;">Lookup</a>
<apex:inputHidden value="{!selectedAccountId}" id="accountId"/>
<script>
var objInputName = '{!$Component.accountName}';
var objInputId = '{!$Component.accountId}';
function popUp()
{
var objAccountInput = document.getElementById(objInputName);
//alert('parameter is ' + document.getElementById(objInputName).value);
var urlAdd = 'vf_AccountLookup_Controller';
if(objAccountInput.value.length > 0)
{
urlAdd += '?srch=' + objAccountInput.value;
//alert('urlAdd is ' + urlAdd);
}
var newWindow = window.open(urlAdd);
}
function setAccount(recordId,recordName)
{
//alert('recordId is ' + recordId);
//alert('recordName is ' + recordName);
document.getElementById(objInputName).value = recordName;
document.getElementById(objInputId).value = recordId;
}
</script>
<br/>
<apex:commandButton value="Assign new account" action="{!changeTheAccount}"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
// The controller for the lookup popup box for selecting new account for a contact.
public class AccountLookup_Controller
{
public String searchText {get;set;}
public List<Account> searchResults {get;set;}
public AccountLookup_Controller()
{
// get search parameter from url if present
if(ApexPages.currentPage().getParameters().containsKey('srch'))
{
searchText = ApexPages.currentPage().getParameters().get('srch');
}
else
{
searchText = '';
}
searchResults = [Select Id, Name, AccountNumber, Site From Account Where Name Like : searchText + '%'];
}
public void searchRecords()
{
searchResults = [Select Id, Name, AccountNumber, Site From Account Where Name Like : searchText + '%'];
}
}
<!--
VF page name :- vf_AccountLookup_Controller
The VF page for the lookup popup box which appears for selecting new account for a contact.
-->
<apex:page controller="AccountLookup_Controller" showHeader="false" sidebar="false">
<apex:form >
<apex:pageBlock >
<apex:sectionHeader title="Select the account to be associated with the contact"/>
<apex:inputText value="{!searchText}" onkeyup="searchImmediately()"/>
<apex:commandButton value="Go" action="{!searchRecords}"
rerender="results"/>
<apex:actionFunction name="searchImmediately" action="{!searchRecords}" reRender="results"/>
<apex:pageBlocksection title="Account Search Results" id="results">
<apex:pageBlockTable value="{!searchResults}" var="a"
rendered="{!searchResults.size>0}">
<apex:column headerValue="Name">
<a style="cursor:pointer;"
onclick="window.opener.setAccount('{!a.Id}', '{!a.Name}');
self.close();">
{!a.name}
</a>
</apex:column>
<apex:column headerValue="Account Number" value="{!a.AccountNumber}"/>
<apex:column headerValue="Account Site" value="{!a.Site}"/>
</apex:pageBlockTable>
<apex:outputText value="No results found"
rendered="{!searchResults.size=0}"/>
</apex:pageBlocksection>
</apex:pageBlock>
</apex:form>
</apex:page>
// The controller for main VF page vfAssignNewAccountToContact
public with sharing class AssignNewAccountToContact
{
public Contact c {get;set;}
public String selectedAccountName {get;set;}
public String selectedAccountId {get;set;}
public AssignNewAccountToContact()
{
selectedAccountName = '';
selectedAccountId = '';
c = [select id, name from Contact where id = :ApexPages.currentPage().getParameters().get('id')];
System.debug('////////////c is ' + c);
}
public pageReference changeTheAccount()
{
System.debug('//////////selectedAccountId is ' + selectedAccountId);
System.debug('//////////selectedAccountName is ' + selectedAccountName);
if(selectedAccountId != '')
{
System.debug('//////////selectedAccountId is not null, so proceeding ');
c.accountId = selectedAccountId;
update c;
ApexPages.addMessage(new ApexPages.message(ApexPages.severity.info, 'New account assigned successfully'));
/*
Make variables null, so that if something is typed now in the textbox,
it gives error message if "Assign new account" is clicked again.
*/
selectedAccountId = '';
selectedAccountName = '';
}
else
{
System.debug('//////////selectedAccountId is null');
ApexPages.addMessage(new ApexPages.message(ApexPages.severity.error, 'Kindly select an account by clicking on Lookup'));
}
return null;
}
}
<!--
VF page name :- vfAssignNewAccountToContact
Main VF page for assigning new account to a contact. Go to an existing contact record and add
/apex/vfAssignNewAccountToContact?id=<ContactRecordID> to the URL to view this VF page.
-->
<apex:page controller="AssignNewAccountToContact">
<apex:form >
<apex:PageMessages id="messages"/>
Click on Lookup to select a new account for this contact and then click on "Assign new account"
<apex:pageBlock title="Contact Details">
Contact name: {!c.name}
<br/>
<apex:pageBlockSection >
<apex:inputText value="{!selectedAccountName}" id="accountName" label="Account"/>
<a onclick="popUp();" style="cursor: pointer;">Lookup</a>
<apex:inputHidden value="{!selectedAccountId}" id="accountId"/>
<script>
var objInputName = '{!$Component.accountName}';
var objInputId = '{!$Component.accountId}';
function popUp()
{
var objAccountInput = document.getElementById(objInputName);
//alert('parameter is ' + document.getElementById(objInputName).value);
var urlAdd = 'vf_AccountLookup_Controller';
if(objAccountInput.value.length > 0)
{
urlAdd += '?srch=' + objAccountInput.value;
//alert('urlAdd is ' + urlAdd);
}
var newWindow = window.open(urlAdd,'Popup','height=500,width=700,left=150,top=50,resizable=no,scrollbars=yes,toolbar=no,status=no');
}
function setAccount(recordId,recordName)
{
//alert('recordId is ' + recordId);
//alert('recordName is ' + recordName);
document.getElementById(objInputName).value = recordName;
document.getElementById(objInputId).value = recordId;
}
</script>
<br/>
<apex:commandButton value="Assign new account" action="{!changeTheAccount}"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
// The controller for the lookup popup box for selecting new account for a contact.
public class AccountLookup_Controller
{
public String searchText {get;set;}
public List<Account> searchResults {get;set;}
public AccountLookup_Controller()
{
// get search parameter from url if present
if(ApexPages.currentPage().getParameters().containsKey('srch'))
{
searchText = ApexPages.currentPage().getParameters().get('srch');
}
else
{
searchText = '';
}
searchResults = [Select Id, Name, AccountNumber, Site From Account Where Name Like : searchText + '%'];
}
public void searchRecords()
{
searchResults = [Select Id, Name, AccountNumber, Site From Account Where Name Like : searchText + '%'];
}
}
<!--
VF page name :- vf_AccountLookup_Controller
The VF page for the lookup popup box which appears for selecting new account for a contact.
-->
<apex:page controller="AccountLookup_Controller" showHeader="false" sidebar="false">
<apex:form>
<script>
window.onblur = function() {
// close this popup window if it loses focus, that is, goes into the background
self.close();
}
document.onblur = window.onblur;
document.focus = window.focus;
</script>
<apex:pageBlock>
<apex:sectionHeader title="Select the account to be associated with the contact"/>
<apex:inputText value="{!searchText}" onkeyup="searchImmediately()"/>
<apex:commandButton value="Go" action="{!searchRecords}"
rerender="results"/>
<apex:actionFunction name="searchImmediately" action="{!searchRecords}" reRender="results"/>
<apex:pageBlocksection title="Account Search Results" id="results">
<apex:pageBlockTable value="{!searchResults}" var="a"
rendered="{!searchResults.size>0}">
<apex:column headerValue="Name">
<a style="cursor:pointer;"
onclick="window.opener.setAccount('{!a.Id}', '{!a.Name}');
self.close();">
{!a.name}
</a>
</apex:column>
<apex:column headerValue="Account Number" value="{!a.AccountNumber}"/>
<apex:column headerValue="Account Site" value="{!a.Site}"/>
</apex:pageBlockTable>
<apex:outputText value="No results found"
rendered="{!searchResults.size=0}"/>
</apex:pageBlocksection>
</apex:pageBlock>
</apex:form>
</apex:page>