Use an Inline Visualforce Page with Standard Page Layouts
May 8th, 2009
Let’s face it, using standard page layouts is easy. Throw some field on the page, arrange some related lists and then essentially forget about the page. However, if you really need to customize the user experience you are almost always forced to write a custom Visualforce page that may require maintenance in the future. But what if you just want to tweak the page layout and give it a little Visualforce bling? Perhaps a custom related list from multiple objects, a Flickr mashup or a Google map of your canary’s current location?
You can now add Visualforce pages to stardard page layouts basically in the same way you can S-Controls. The use case is that you have accounts with hundreds of opportunities each and users are getting tired of scrolling through pages and pages of records to find the ones that they need. Let’s develop a Visualforce page and controller extension that provides them with a opportunity search interface on the account details page.
Here’s what the final application looks like:
First we need to create the Visualforce page and controller extension. Our Visualforce page must use the standard Account controller or it will not show up on the list of available Visualforce pages on the page layout.
OpportunitySearchController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public class OpportunitySearchController {
//added an instance varaible for the standard controller
private ApexPages.StandardController controller {get; set;}
// the actual account
private Account a;
// the results from the search. do not init the results or a blank rows show up initially on page load
public List<opportunity> searchResults {get;set;}
// the text in the search box
public string searchText {
get {
if (searchText == null) searchText = 'Acme'; // prefill the serach box for ease of use
return searchText;
}
set;
}
public OpportunitySearchController(ApexPages.StandardController controller) {
//initialize the stanrdard controller
this.controller = controller;
this.a = (Account)controller.getRecord();
}
// fired when the search button is clicked
public PageReference search() {
if (searchResults == null) {
searchResults = new List<opportunity>(); // init the list if it is null
} else {
searchResults.clear(); // clear out the current results if they exist
}
// Note: you could have achieved the same results as above by just using:
// searchResults = new List<categoryWrapper>();
// use some dynamic soql to find the related opportunities by name
String qry = 'Select o.Id, o.Name, o.StageName, o.CloseDate, o.Amount from Opportunity o Where AccountId = \''+a.Id+'\' And o.Name LIKE \'%'+searchText+'%\' Order By o.Name';
searchResults = Database.query(qry);
return null;
}
} |
Inline_Opportunity_Search
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<apex:page standardController="Account" extensions="OpportunitySearchController">
<style type="text/css">
body {background: #F3F3EC; padding-top: 15px}
</style>
<apex:form >
<apex:pageBlock title="Search for Opportunities by Keyword" id="block" mode="edit">
<apex:pageMessages />
<apex:pageBlockSection >
<apex:pageBlockSectionItem >
<apex:outputLabel for="searchText">Keyword</apex:outputLabel>
<apex:panelGroup >
<apex:inputText id="searchText" value="{!searchText}"/>
<apex:commandButton value="Search" action="{!search}" rerender="resultsBlock" status="status"/>
</apex:panelGroup>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
<apex:actionStatus id="status" startText="Searching... please wait..."/>
<apex:pageBlockSection id="resultsBlock" columns="1">
<apex:pageBlockTable value="{!searchResults}" var="o" rendered="{!NOT(ISNULL(searchResults))}">
<apex:column headerValue="Name">
<apex:outputLink value="/{!o.Id}">{!o.Name}</apex:outputLink>
</apex:column>
<apex:column value="{!o.StageName}"/>
<apex:column value="{!o.Amount}"/>
<apex:column value="{!o.CloseDate}"/>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page> |
Now all you simply have to do is add this new Visalforce page to your page layout and you’re a hero!
Categories: Apex, Code Sample, Salesforce, Visualforce















Thanks for share this information !
Could you use this approach on custom object to over come the 2 column limitation on page layouts?
@Dan, I don’t see why you couldn’t? You have essentially complete control over the Visualforce page.
Hi,
Is it possible to show the inline VF in edit mode of the detail page. Supposing I have a VF in my opty detail page, in which I have some opty fields. When I click on Edit button, in the opty detail page, this VF section is not shown. How can I make that available?
Thanks,
Hi Jeff,
When I add the Visualforce page to the standard layout, I must set its height to a fixed pixel value (only width can have a variable %), Any ideas on how I can avoid having the area scroll when the embedded page needs a little more height.
Best,
Brent
@Archana, I don’t think this is possible. You’ll probably have to go to an entire visualforce page.
@Brent, it’s a clumsy solution but you can adjust the size with Javascript and the DOM. Unfortunately I don’t have the code. You may want to drop @wesnolte a line and see if he can help.
I am a developer who is new to PeopleSoft. I have created a dispatcher class in apex. The apex class needs to redirect the user to either a full-access account layout page or a limited-access account layout page, depending on whether or not the owner of the account is the currently logged in user. Therefore, I need to access a page layout from apex code (or embed an account page layout in a VisualForce page). Any ideas on how to do the inverse of what you have posted here? Thanks,
Hi Jeff, Brent,
We got an AppExchange package available for the automatic height adjustment of inline visualforce pages. You can try it out and let me know your thoughts, it’s free
https://sites.secure.force.com/appexchange/listingDetail?listingId=a0N30000004cEEyEAM#
It was a bit complex to get javascript and DOM sizing to work with XSS (Cross-Site Scripting), which is considered browser security feature. We used EasyXDM.net library that includes a number of protocols to ensure browser support. IE8, Firefox, Chrome and Safari have been tested to work.
Jeff, I could use this chance to thank you for the information you’ve provided on your blog, a couple of your entries saved hours of troubleshooting in the past, thanks!
Dmitri
@Brent and @Jeff
here is the JS code that you could use to adjust the inline page hight …
———————————————————————————
window.onload=adjustHeight;
function adjustHeight(){
var iframeId = getIframeID();
var if1 = parent.document.getElementById(iframeId);
var ca = document.getElementById(“{!$Component.caID}”);
if1.height = ca.offsetHeight;
}
function getIframeID(el){
var myTop = top;
var myTitle = ‘YOUR_PAGE_NAME_HERE’;
var iFs = top.document.getElementsByTagName(‘iframe’);
var x, i = iFs.length;
while ( i– ){
x = iFs[i];
if (x.title == myTitle){
return x.id;
}
}
return ‘Couldn\’t find the iframe’;
}
——————————————————————————
Did the code for the VF page disappear or something?
Thanks for the heads up. The plugin that I was using stopped working. It should be displaying properly now.
How to refresh the page layout if the VF page updates field values?