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

Leave a comment

Comments Feed38 Comments

  1. MatLeete

    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?

  2. jeffdonthemic

    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

  3. Josh

    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

  4. Kyle Freeman

    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?

  5. jaw

    I am having trouble getting the redirected record to load my Contact_View_1 – or anything but the header and sidebar.

  6. jeffdonthemic

    Can you send me post or send some code and I’d be glad to take a look.

  7. jaw

    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.

  8. jaw

    whoops, my contact_view_1 page didn’t show -
    here (simplified)
    (apex:page standardController=”contact”)
    (apex:detail /)
    (/apex:page)

  9. jaw

    Any tips, Jeff?

  10. jeffdonthemic

    Can you email me your code and I’ll take a look at it? jeffdonthemic at gmail dot com

  11. Kautuk

    Jeff, How and where are you calling the getRedir method?

  12. jeffdonthemic

    Sorry… it looks like WordPress crushed my code. I have restored it. Thanks!

  13. Rob Craven

    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))}”

  14. Rob Craven

    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.

  15. Rob Craven

    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.

  16. rubixtious

    I am having the same issue. Could you post some code on how you got this working? Thanks

  17. Vishnu

    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.

  18. Rob Craven

    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

  19. Rob Craven

    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

  20. Niki Vankerk

    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=.

  21. Raj Tahil

    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;
    }

    }

  22. jeffdonthemic

    Raj, this might be better posted on the Support message boards.

  23. Miguel Chinchilla

    Hi, Rob.

    Need to know if you solved the problem when you implement the “New” cod. How?

    Thanks.

  24. Rob Craven

    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.

  25. Miguel Chinchilla

    Thansk Rob,

    I really appreciate your help.

    Regards.

  26. rubixtious

    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

  27. Miguel Chinchilla

    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.

  28. MMA

    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

  29. MMA

    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

  30. Simson

    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.

  31. Jeff Douglas

    Check your ContactStandardController class and make sure you have a method named redirect and that it is public.

  32. Ben

    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.

  33. Ben0034

    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?

  34. Jeff Douglas

    Could you change your code so that if the recordtype is null then look up current user’s default recordtype or store that somehow?

  35. Force Architects: Delivered Innovation Blog » Force.com Tip: 'New' Button Override to Assign VisualForce Page to Specific Record Type Using Native Apex Code

    [...] Jeff Douglas has provided another method for achieving automated redirection to VisualForce pages on his blog.  You can find the link here. [...]

  36. Suresh

    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

  37. Brian Kessler

    @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?

  38. Raghu

    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?

Leave a comment

Feed

http://blog.jeffdouglas.com / Redirecting Users to Different Visualforce Pages

WordPress Appliance - Powered by TurnKey Linux