Mimic Task Subject Lookup in sControl
From time to time, there may be a need to mimic the lookup functionality from standard salesforce.com edit pages into a custom sControl. In this example, I am going to show you how to mimic the lookup field for "subject" that you would normally find on the Task edit page.
The concepts covered in this example are built off some other concepts I've already done examples for on this site so please feel free to review some of our other examples prior to trying this one.
When you read the title of this post you might think that the topic should be pretty straight-forward and not require too much code. As you will soon read, this functionality is a little tricky and there are some really useful functions incorporated into the final result which you can use in other sControls.
The first part of this sControl are the usual include files. These include the style sheets and JavaScript files from salesforce.com:
<!-- common styles --><link href="/sCSS/10.0/Theme2/common.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- standard styles --><link href="/sCSS/10.0/Theme2/dStandard.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- element styles --><link href="/sCSS/10.0/Theme2/elements.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- AJAX Toolkit version 10.0 --><script src="/soap/ajax/10.0/connection.js" type="text/javascript"></script>
<!-- salesforce.com specific functions --><script src="/js/functions.js" type="text/javascript"></script>
Depending on your salesforce.com Org setup you may use Record Types on the Task object. If this is the case then it is entirely possible for the "Subject" field options to be different for your various users based upon their assigned profile. For this reason, we cannot simply query for all picklist values for "Subject". You must use the picklist values defined in the DescribeLayout API call from the AJAX toolkit. I wrote that function here:
//using the describeLayout call we can pull back an array of picklist values for a specific field on a specific table.
function getPicklistValues(object,field) {
var returnArray = new Array(); //declaration for array to be returned
var DescribeLayoutResult = sforce.connection.describeLayout(object); //intatiate the describeLayout call for the passed object
var recordTypeMap = DescribeLayoutResult.recordTypeMappings; //get into the portion of the response where the Layout settings are defined
var a; //declaration for later loop
for (a in recordTypeMap) { //loop through all the recordType options
if (recordTypeMap[a].defaultRecordTypeMapping=="true") { //if we find the default layout
var picklistOptions = recordTypeMap[a].picklistsForRecordType; //get into the portion of the response where recordType details are defined
var b; //declaration for later loop
for (b in picklistOptions) { //for all defined picklists
if (picklistOptions[b].picklistName==field) { //if the field we passed to the function is the picklist we are at
var c; //declaration for later loop
for (c in picklistOptions[b].picklistValues) { //loop through all the values for this field
returnArray.push(picklistOptions[b].picklistValues[c].label); //push the label to the returnArray
}
}
}
}
}
return returnArray; //send back the array
}
What you'll notice about the code above is that the thing needs to be told which object and field for which you want picklist options. It will then return the options in an array.
Next we'll look at the field layout for the page. We are technically going to hijack the standard lookup that salesforce designed. The nice part about doing this is that when the user clicks the lookup, we simply pass a couple of parameters and the pop-up window knows what to do with them.
<input id="subject" maxlength="80" name="subject" size="75" type="text" value=""> <a href="JavaScript: openPopupFocus('/widg/combobox.jsp?form=editPage&field=subject&display=1&cnt=10', '_blank', 270, 200, 'width=270,height=200,resizable=yes,toolbar=no,status=no,scrollbars=yes,menubar=no,directories=no,location=no,dependant=yes', true, true);" onclick="setLastMousePosition(event)" title="combo (New Window)"><img src="/s.gif" alt="Subject combo (New Window)" class="comboboxIcon" onblur="this.className = 'comboboxIcon';" onfocus="this.className = 'comboboxIconOn';" onmouseout="this.className = 'comboboxIcon';this.className = 'comboboxIcon';" onmouseover="this.className = 'comboboxIconOn';this.className = 'comboboxIconOn';" title="Subject combo (New Window)"></a>
Most of the code above is formatting and display that the page will use to handle changing the lookup icon on mouseover and other interactions. The most important part of the code above is the piece reading "?form=editPage&field=subject&display=1&cnt=10".
The "?form=editPage" tells the combobox lookup window that the field requesting the subject information is inside a form named "editPage". You can call the form anything you want just make sure to update the FORM tag in your HTML and the "?form=editPage" section of the code above.
The "&field=subject" portion of the code tells the lookup window which field to drop the selection into when one is made.
One thing you'll notice when you click the lookup for a subject in salesforce.com is that there is one option for selection on each line in the resulting window. The "&cnt=10" portion of the code (from the block above) tells the lookup window how many subjects to display in the lookup (the number of lines). What this essentially means is that you'll have to dynamically populate that value in the code so that you always include the correct number of rows for the subject values as your subject values may change on the fly & over time.
The last thing I want to point out before getting to the final code is that the lookup window needs to be told which values to display. Basically, the picklist values are pulled from a global variable set on the page from where the lookup is accessed. To populate the global variable with the correct picklist values for the running user, you will need to call the "getPicklistValues()" function and assign the results to that global variable. In my example I am using "cb_subject" as the global. See the code below:
window["cb_subject"] = getPicklistValues("Task","Subject");
Here is the full code for you to copy & paste into your own sControl.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Mimic Subject Lookup</title>
<!--
Created by: Greg Hacic
Last Update: October 23, 2007
Questions?: greg@interactiveties.com
(c)2007 Interactive Ties LLC
-->
<!-- common styles --><link href="/sCSS/10.0/Theme2/common.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- standard styles --><link href="/sCSS/10.0/Theme2/dStandard.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- element styles --><link href="/sCSS/10.0/Theme2/elements.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet">
<!-- AJAX Toolkit version 10.0 --><script src="/soap/ajax/10.0/connection.js" type="text/javascript"></script>
<!-- salesforce.com specific functions --><script src="/js/functions.js" type="text/javascript"></script>
<script language="javascript">
function pageInit() {
try {
//window["..."] allows me to access the global variable declared above dynamically
window["cb_subject"] = getPicklistValues("Task","Subject"); //get all the picklist values for subject
document.getElementById("subject_Placeholder").innerHTML = "<div class=\"requiredBlock\"></div><input id=\"subject\" maxlength=\"80\" name=\"subject\" size=\"75\" type=\"text\" value=\"\"> <a href=\"JavaScript: openPopupFocus('/widg/combobox.jsp?form=editPage&field=subject&display=1&cnt="+window["cb_subject"].length+"', '_blank', 270, 200, 'width=270,height=200,resizable=yes,toolbar=no,status=no,scrollbars=yes,menubar=no,directories=no,location=no,dependant=yes', true, true);\" onclick=\"setLastMousePosition(event)\" title=\"combo (New Window)\"><img src=\"/s.gif\" alt=\"Subject combo (New Window)\" class=\"comboboxIcon\" onblur=\"this.className = 'comboboxIcon';\" onfocus=\"this.className = 'comboboxIconOn';\" onmouseout=\"this.className = 'comboboxIcon';this.className = 'comboboxIcon';\" onmouseover=\"this.className = 'comboboxIconOn';this.className = 'comboboxIconOn';\" title=\"Subject combo (New Window)\"></a>";
} catch(e) {
alert(e);
}
}
//using the describeLayout call we can pull back an array of picklist values for a specific field on a specific table.
function getPicklistValues(object,field) {
var returnArray = new Array(); //declaration for array to be returned
var DescribeLayoutResult = sforce.connection.describeLayout(object); //intatiate the describeLayout call for the passed object
var recordTypeMap = DescribeLayoutResult.recordTypeMappings; //get into the portion of the response where the Layout settings are defined
var a; //declaration for later loop
for (a in recordTypeMap) { //loop through all the recordType options
if (recordTypeMap[a].defaultRecordTypeMapping=="true") { //if we find the default layout
var picklistOptions = recordTypeMap[a].picklistsForRecordType; //get into the portion of the response where recordType details are defined
var b; //declaration for later loop
for (b in picklistOptions) { //for all defined picklists
if (picklistOptions[b].picklistName==field) { //if the field we passed to the function is the picklist we are at
var c; //declaration for later loop
for (c in picklistOptions[b].picklistValues) { //loop through all the values for this field
returnArray.push(picklistOptions[b].picklistValues[c].label); //push the label to the returnArray
}
}
}
}
}
return returnArray; //send back the array
}
</script>
</head>
<body onload="pageInit();" class="taskTab editPage">
<form id="editPage" name="editPage">
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td>
<div class="bPageTitle">
<div class="ptBody secondaryPalette">
<div class="content"><img src="/s.gif" alt="Home" class="pageTitleIcon"><h1 class="pageType">Sample<span class="titleSeparatingColon">:</span></h1><h2 class="pageDescription"> Subject Lookup</h2><div class="blank"> </div>
</div>
</div>
<div class="ptBreadcrumb"></div>
</div>
<div class="filterOverview">Mimic the "Subject" lookup field from Task creation screen. Pulls subject options specific to running user's Profile.</div>
<div class="bRelatedList" id="tableResults">
<div class="bPageBlock secondaryPalette"><div class="pbHeader"><table cellpadding="0" cellspacing="0" border="0"><tr><td class="pbTitle"><img src="/s.gif" alt="" title="" width="1" height="1" class="minWidth"><img src="/s.gif" alt="" class="relatedListIcon"><h3 class="bodyBold">Results Area</h3></td><td class="pbButton"> </td></tr></table></div>
<div class="pbBody">
<div class="pbSubheader first tertiaryPalette"><span class="pbSubExtra"><span class="requiredLegend"><span class="requiredExampleOuter"><span class="requiredExample"> </span></span><span class="requiredText"> = Required Information</span></span></span><h3>Information<span class="titleSeparatingColon">:</span></h3></div>
<div class="pbSubsection">
<table class="detailList" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="labelCol requiredInput"><label for="subject"><span class="requiredMark">*</span>Subject</label></td>
<td class="data2Col" colspan="3"><div class="requiredInput"><div class="requiredBlock"></div><span id="subject_Placeholder">Loading...</span></div></td>
</tr>
<tr>
<td class="labelCol empty last"> </td>
<td class="dataCol col02 empty last"> </td>
<td class="labelCol empty last"> </td>
<td class="dataCol empty last"> </td>
</tr>
</table>
</div>
</div>
<div class="pbBottomButtons"><table border="0" cellpadding="0" cellspacing="0"><tr><td class="pbTitle"><img src="/s.gif" alt="" width="1" height="1" class="minWidth" title=""> </td><td class="pbButtonb" id="buttonsBottom"> </td></tr></table></div>
<div class="pbFooter secondaryPalette"><div class="bg"></div></div>
</div>
</div>
</td>
</tr>
</table>
</form>
</body>
</html>
I hope this illustrates how you can incorporate standard salesforce.com functionality into your sControl to save both time and money on development.