Redirecting Users to Different Visualforce Pages
November 14th, 2008
We have a large Salesforce.com org with 400+ recordtypes and 600+ page layouts. When Visualforce was released we wanted to start developing customized Visualforce pages for certain recordtypes. Unfortunately, you cannot assign Visualforce pages by recordtype so you have to implement a hack around it.
Note: There is currently as issue with Visualforce in that inputFields do not respect recordtypes. So if you have picklists with values for different recordtypes, your picklists on your Visualforce pages will show all picklist values and not just those values for that recordtype. There is a thread relating to this on the force.com discussion boards but Sam Arjmandi has posted a picklist component for a workaround.
What you need to do is create a “dispatcher” Visualforce page (Dispatcher_Contact_View.page) and accompanying controller extension (DispatcherContactViewController.cls) and then override the appropriate button/link action (view, edit or new) with this new dispatcher Visualforce page. The code is slightly different depending on whether you are doing view, edit or new so I’ll be showing them all. When a user clicks the view button/link for appropriate object, it loads the new Visualforce page. The Visualforce page loads the controller extension and perform some logic to determine if the user should be dispatched to your new view page (Contact_View_1) or the standard Salesforce.com view page.
You’ll need to override each button to call the specific Visualforce page. Here’s more info on how to do that.
Dispatcher_Contact_View.page
1 2 3 | <apex:page standardController="Contact" extensions="DispatcherContactEditController" action="{!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))}"> </apex:page> |
DispatcherContactViewController.cls
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 | public class DispatcherContactViewController { public DispatcherContactViewController(ApexPages.StandardController controller) { this.controller = controller; } public PageReference getRedir() { Contact c = [Select id, recordtypeid From Contact Where Id = :ApexPages.currentPage().getParameters().get('id')]; PageReference newPage; if (c.recordtypeid == '111111111111') { newPage = Page.Contact_View_1; } else { newPage = new PageReference('/' + c.id); newPage.getParameters().put('nooverride', '1'); } newPage.getParameters().put('id', c.id); return newPage.setRedirect(true); } private final ApexPages.StandardController controller; } |
The code is somewhat similar for the edit and new use cases but does have some notable differences.
Dispatcher_Contact_Edit.page
1 2 3 | <apex:page standardController="Contact" extensions="DispatcherContactEditController" action="{!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))}"> </apex:page> |
DispatcherContactEditController.cls
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 | public class DispatcherContactEditController { public DispatcherContactEditController(ApexPages.StandardController controller) { this.controller = controller; } public PageReference getRedir() { Contact c = [Select id, recordtypeid From Contact Where Id = :ApexPages.currentPage().getParameters().get('id')]; PageReference newPage; if (c.recordtypeid == '111111111111') { newPage = Page.Contact_Edit_1; } else { newPage = new PageReference('/' + c.id + '/e'); newPage.getParameters().put('nooverride', '1'); } newPage.getParameters().put('id', c.id); return newPage.setRedirect(true); } private final ApexPages.StandardController controller; } |
Dispatcher_Contact_New.page
1 2 3 | <apex:page standardController="Contact" extensions="DispatcherContactNewController" action="{!nullValue(redir.url, urlFor($Action.Contact.New, null, null, true))}"> </apex:page> |
DispatcherContactNewController.cls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class DispatcherContactNewController { public DispatcherContactNewController(ApexPages.StandardController controller) { this.controller = controller; } public PageReference getRedir() { PageReference newPage; if (ApexPages.currentPage().getParameters().get('RecordType') == '111111111111') { newPage = Page.Contact_New_1; return newPage.setRedirect(true); } else { return null; } } private final ApexPages.StandardController controller; } |
Categories: Apex, Code Sample, Salesforce, Visualforce













Hi Jeff
Good read, I have one question more about your use of RecordType in general, I am interested in the reason why you have ended up with 400+ of them.
I understand the basic concept of them to control picklists and layouts, but why so many?
I am looking at them to control editing for records in given states i.e. stopping edit’s after an record approved. Are RecordType the only tool from the standard SalesForce toolbag?
We run “a large” number of distinct companies within our Org with roughly 2000 users. We utilize recordtypes to separate out access to page layouts, picklist values, records, etc. so that users from one company have a different UI experience than users from another company. HTH
First of all congratulation for such a great site. I learned a lot reading here today. I will make sure i visit this site more often so I can learn more.
Make your long Urls shorter – Free Url redirection – Hide your affilate URLS
I looked into the picklist component you linked to, but it doesn’t appear that it helps to handle RecordType filtering of picklists. Are you sure that it can be used to handle this?
I am having trouble getting the redirected record to load my Contact_View_1 – or anything but the header and sidebar.
Can you send me post or send some code and I’d be glad to take a look.
Jeff, thanks, I kept everything very simple, just copying your code, subbing in my record type id. It works in that the other record type gets the standard view.
For my contact_view_1 after it wasn’t working I simplified it to:
and it never loads – the url in my page is still Dispatcher_Contact_View?id=00(etc).
but weirdly, if I use another object for the say, make it “case” – the contact loads with all detail, but in the case page style.
whoops, my contact_view_1 page didn’t show -
here (simplified)
(apex:page standardController=”contact”)
(apex:detail /)
(/apex:page)
Any tips, Jeff?
Can you email me your code and I’ll take a look at it? jeffdonthemic at gmail dot com
Jeff, How and where are you calling the getRedir method?
Sorry… it looks like WordPress crushed my code. I have restored it. Thanks!
Jeff, great post, you Rock!
I’m having a slight issue implementing the “New” code. It redirects to the VF page when matched on record type… but when returning null the urlFor is not redirecting the page to the Standard object New interface… Instead it just keeps redirecting back to the record type selection page?
The urlFor looks correct?
action=”{!nullValue(redir.url, urlFor($Action.Ticket_Data_Form__c.New, null, null, true))}”
I gave up on implementing the “New” redirects via VF, could never get the URLFOR to work right. I’ve instead implemented via an S-Control. Basically create the object and pass the id value to an VF edit page.
Using the Dispatcher_Contact_Edit.page, I’ve noticed odd behaviour, just not sure what the issue is. Basicly, if your attempting to redirect to a VF page that only contains a standard controller the redirect hangs. For whatever reason your VF page must include a controller extension for the redirect to work correctly.
I am having the same issue. Could you post some code on how you got this working? Thanks
Your post seems to be relevent.. kindly let me know how to redirect to parent page from a visualforce page. In a visualforce page am doing an action once the action is complete, i want to redirect to same page. I tried with retUrl ,it was in vain.
This comment box will not except code, sorry.
Create an S-Control and set it up as the override page for the “New” action. Once this is done your S-Control page will have access to the following merge field {Object.RecordTypeId}, since the record type page is displayed prior to this S-Control page.
Use branching based on this record type id….
If a VF page should be displayed, create sobject with record type id and default values. Next set a var for url = “apex/page?id=” your new record id. You should also set the retURL, and cancelURL properties. Next set parent.location.href = yourNewUrl
Else redirect to the standard page
url = parent.location.href
url += &nooverride=1
parent.location.href = url
Ensure the script runs during the onload event
Create method
public PageReference getRedir()
PageReference newPage
If recordtype id = ‘x’
newPage = Page.vfPageName
else if recordtype id = ‘z’
newPage = Page.vfPageName
else
newPage = newPageReference(‘/’ + idOfCurrentRec + ‘/e’)
NewPage.getParameters().put(‘nooverride’, ’1′)
end if
//add common url values..(id, retURL)
return newPage.setRedirect(true);
end function
I was able to get the New redirect working after selecting a RecordType. Instead of using the URLFOR($Action.Object.New) in my page action parameter, I used URLFOR(‘//e?nooverride=true&RecordType=’+.RecordTypeId). For the Opp it would be URLFOR(‘/006/e?nooverride=true&RecordType=’+Opportunity.RecordTypeId)
Note: the URL is case sensitive so you need to put capitals on RecordType=.
Hi.. I have written one standard controller with custom extension.
Whenever user enters value in the Visualforce page and click on Save Button, field value is actually not getting save in the record. So can you please let me know what function is to be written in Apex class for Save button
Standard Contoller:
Agent Name
{!c.name}
Previous
Next
First
Last
Apex Clas:
public class ContactPage
{
private User varuser { get; private set;}
private Profile prof { get; private set;}
private final Contact cont { get; private set;}
public ContactPage(ApexPages.StandardSetController controller)
{
this.cont = (Contact)controller.getRecord();
}
public ApexPages.StandardSetController contactRecords{
get
{
id id1 = userinfo.getProfileId();
id id2 = userinfo.getUserId();
prof = [Select Name from Profile where Id= :id1];
varuser =[Select IsActive , Name from User where Id= :id2];
if(contactRecords == null && id2 != NULL && id1 != null && prof.Name == ‘RI Sales External Wholesalers Profile’ && varuser.IsActive ==true)
{
return new ApexPages.StandardSetController(Database.getQueryLocator(
[SELECT Id, name, AccountId, RI_DriveTo_City__c, RI_DriveTo_State__c, RI_DriveTo_Zip__c, RI_Current_YTD__c, RI_Prior_YTD__c, RI_Production_Goals_This_Year__c, RI_Production_Goals_Next_Year__c, Face_to_Face_Activity_Goal__c, RI_Zone__c, RI_Segment__c, Projected_Sequoia_Seg__c, Tertiary_Territory__c FROM Contact WHERE recordtypeid = '012400000005OLAAA2' and ownerid = :id2 order by RI_Current_YTD__c desc Limit 1000]));
}
else if(contactRecords == null && id2 != NULL && id1 != null && (prof.Name == ‘System Administrator’ || prof.Name == ‘RI Sys Admin’) && varuser.IsActive ==true)
{
return new ApexPages.StandardSetController(Database.getQueryLocator(
[SELECT Id, name, AccountId, RI_DriveTo_City__c, RI_DriveTo_State__c, RI_DriveTo_Zip__c, RI_Current_YTD__c, RI_Prior_YTD__c, RI_Production_Goals_This_Year__c, RI_Production_Goals_Next_Year__c, Face_to_Face_Activity_Goal__c, RI_Zone__c, RI_Segment__c, Projected_Sequoia_Seg__c, Tertiary_Territory__c FROM Contact WHERE recordtypeid = '012400000005OLAAA2' order by RI_Current_YTD__c desc Limit 1000]));
}
else if(contactRecords == null && id2 != NULL && id1 != null && prof.Name != ‘System Administrator’ && prof.Name != ‘RI Sales External Wholesalers Profile’ && prof.Name != ‘RI Sys Admin’ && prof.Name !=NULL )
{
}
return contactRecords;
}
private set;
}
public List getContactPagination() {
return (List) contactRecords.getRecords();
}
public PageReference save()
{
PageReference pageRef= new PageReference(‘/apex/BusReport’);
pageRef.setredirect(true);
return pageRef;
}
}
Raj, this might be better posted on the Support message boards.
Hi, Rob.
Need to know if you solved the problem when you implement the “New” cod. How?
Thanks.
S-Control you create the record up front with record type and then redirect to that record id…..follow the instructions listed in my Sept 24, 09 comment related to this thread. Please note, I’ve also voiced this issue at Dreamforce 09 during a code consultant review, the URLFOR is not working as intended when using action.NEW? I’m not sure why, hope to provide more answers soon.
Thansk Rob,
I really appreciate your help.
Regards.
I managed to get the new redirect page working using native visualforce. An outline of the solution is here:
http://community.salesforce.com/sforce/board/message?board.id=Visualforce&thread.id=16528
Hello friends, I need your help again in Visualforce. I have a selectList, where I choose a value (eg colony) SelectOption (IdZona, colony name)use in class. I need to select a colony takes the IdZona and find the value in the object Zona__c and the name of the area put it in a inputField.
Thanks a lot.
Do you have a testmethod for this cause I am totally lost with my testmethod on override a new button on opportunity…
This is my posting on Salesforce.com Apex Board
http://community.salesforce.com/sforce/board/message?board.id=apex&thread.id=23824
Would you happen to have a testmethod on this… I am so lost with my testmethod .. I have post it up on the Apex board here is the link:
http://community.salesforce.com/sforce/board/message?board.id=apex&thread.id=23824&view=by_date_ascending&page=2
Any help is appreciated…
Happy Holidays
Thanks
Hi Jeff,
i am getting an error while trying to implement the code for new Contact.
The error on the dispatcher Visualforce page is “Unknown Property ‘ContactStandardController.redirect’.
This VF page has the following code:
i have a controller extension called DispatcherForNewContactController which has the redirect method.
Can you please provide me a pointer on this error.
Check your ContactStandardController class and make sure you have a method named redirect and that it is public.
Thanks for the tip- This is a useful pattern for all sorts of VF maneuvers we do at our shop. There are many cases where we want to dispatch to a given page based on combinations of fields on the records, and the user making request.
Thanks, Jeff! This page redirection works great, except for one scenario we have…
We have multiple record types, but some of our users have access to only one opportunity record type. They are not prompted for a record type when creating a new opportunity record, so therefore the RecordTypeId parameter does not exist on the URL.
Based on the user’s 1 default record type, they should be directed to the custom VF page. When the redirection Controller code runs, it does not correctly redirect the user to the custom VisualForce page since the record type is not on the URL.
I tried getting the current record’s recordtypeid in the Controller, but it comes up null since the record has not been created yet.
Any other suggestions?
Could you change your code so that if the recordtype is null then look up current user’s default recordtype or store that somehow?
[...] Jeff Douglas has provided another method for achieving automated redirection to VisualForce pages on his blog. You can find the link here. [...]
While using $Action.Contact.New I getting the following error Error: Field $Action.Contact.New does not exist. Check spelling What could be the possible reason
@Suresh – I get the same error. Seems strange since we can certainly add new contacts (otherwise there would be nothing to view or edit). Did you ever find a fix?
Thanks Jeff.. I have the implemented the same scenario in my org but i would like the Visualforce to consider the recordtype and display the picklist values accordingly. But not able to achieve this functionality following this method. It works only if i override the new button with a single visualforce page. Any thoughts on how this can be done?