+ Start a Discussion
arasuarasu 

Visualforce page edit button override and page redirect not working?

Hi,
 
I need to override the standard edit page for a custom object. If the status of the custom object record is "Approved", then I do not want users to edit the record, else I need to redirect the users to the standard edit page for this record.
 
I have the following code in VF and controller. I can see the the URL is changed to the edit page URL when I click the edit button after overiding the button with the VF page, but the standard edit page is not getting displayed. Insatead the word Hello is getting displayed.
 
VF Code:
<apex:page standardController="Fixture_Order__c" extensions="conSEditOverrideFixtureOrder" 
id="mypage">
Hello
</apex:page>

 
Controller Code:
public class conSEditOverrideFixtureOrder {
Fixture_Order__c fixordobj; 

private String vid; 


public conSEditOverrideFixtureOrder(ApexPages.StandardController controller) { 

this.vid = ApexPages.currentPage().getParameters().get('id'); 
reset();

} 

public PageReference reset() { 

if(fixordobj.Approval_Status__c=='Approved'){
 PageReference editPage = new PageReference('/'+this.vid+'/e—retURL=' + this.vid);
 editPage.setRedirect(true);
 return editPage;
}else{
PageReference errPage = new PageReference('/apex/editFixtureOrderError');
 errPage.setRedirect(true);
 return errPage;
 
}

return null; 

} 

public String getApprovalStatus(){
 return this.fixordobj.Approval_Status__c;
}

public Fixture_Order__c getFixtureOrder() { 

if(fixordobj == null) reset(); 

return fixordobj; 

} 


public void setLead(Fixture_Order__c leaddet) { 

fixordobj = leaddet; 

} }

 

Can anyone please help to understand the cause? Appreciate all your valuable feedbacks.

Thanks and regards,
Ambili
Best Answer chosen by Admin (Salesforce Developers) 
dchasmandchasman
You are correct that urlFor() is not currently available in apex but you can combine VF expressions and apex code (might not even need apex code in this case) to accomplish your goal. Also, i have cleaned up a couple of things in your controller extension (e.g. leveraged the Page collection instead of hard coding string refs to pages):

Code:
<apex:page standardController="Contact" extensions="dispatcherContactEditController" 
action="{!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))}">
</apex:page>

public class dispatcherContactEditController {
public dispatcherContactEditController(ApexPages.StandardController controller) {
this.controller = controller;
}

public PageReference getRedir() {
PageReference newPage = null;
Contact c = (Contact)controller.getRecord();

if (c.recordtypeid == '00000000') {
newPage = Page.Contact_Edit1;
} else if (c.recordtypeid == '11111111') {
newPage = Page.Contact_Edit2;
}

if (newPage != null) {
newPage.getParameters().put('id', c.id);
}

return newPage;
}

private final ApexPages.StandardController controller;
}

 Depending on your page you may need to add a non displaying reference into your markup to let the standard controller know about the reference to contact.recordTypeId in your action method - something like this anywhere in your page should work:

Code:
<apex:outputText value="{!contact.recordTypeId}" rendered="false"/>

 and for a totally apex code free solution:

Code:
{!urlFor(case(contact.recordTypeId, '012300000004pYzAAI', $Page.contact_edit1, '11111111', $Page.contact_edit2, $Action.Contact.Edit), contact.id, [id = contact.id], true)}




Message Edited by dchasman on 09-19-2008 04:52 PM

Message Edited by dchasman on 09-19-2008 05:44 PM

All Answers

jwetzlerjwetzler
Just calling reset() in your constructor is not actually going to cause your page to redirect, it's just throwing away the PageReference you're returning.  You want to use the action attribute on apex: page to call your reset action on page load.
arasuarasu

Hi,

Thanks a lot for your reponse. Initially I started with using the action attribute in the apex:page tag. But when I had the following code inthe VF page, it was throwing "Syntax Error" for the line {!Fixture_Order__c.Approval_Status__c}.  So it appeared that at the apex:page level, probably it does not understand the syntax {!Fixture_Order__c.Approval_Status__c}. Is that true or am I doing something wrong here?

VF Code with action attribute:
<apex:page standardController="Fixture_Order__c" extensions="conSEditOverrideFixtureOrder"
action="{!if({!Fixture_Order__c.Approval_Status__c}=='Approved', null, URLFOR($Action.Fixture_Order__c.edit, Fixture_Order__c.Id, [retURL=URLFOR($Action.Fixture_Order__c.View, Fixture_Order__c.Id)], true))}"
id="mypage" >
Hello
</apex:page>


 Thanks for all your feedbacks.

Regards,

Ambili

jwetzlerjwetzler
action="{!reset}" ?
jwetzlerjwetzler
Also your sytax errors are because you are nesting your {! }, you only need one.
arasuarasu

Hi,

Thanks again for your prompt response.

I tried the above by calling the reset in action. I think its trying to work, but its going in an endless loop by refreshing the page endlessly. Is this becasue the edit button is overriden and hence everytime it is trying to load the standard edit page, the VFpage code gets executed? If so, how can I get this to work without going in an endless loop.

Our requirement is basically to not allow the users to go to the edit page, if the status of the record is "Approved", else it should allow to go to the standard edit page for this custom object.

Appreciate all help. Thanks.

Controller method for reset Code:
public PageReference reset() { 
this.vid = ApexPages.currentPage().getParameters().get('id'); 
fixordobj=[Select Id,Approval_Status__c from Fixture_Order__c where Id=:vid];
if(fixordobj.Approval_Status__c!='Approved'){
 PageReference editPage = new PageReference('/'+this.vid+'/e—retURL=' + this.vid);
 editPage.setRedirect(true);
 return editPage;
}else{
PageReference errPage = new PageReference('/apex/editFixtureOrderError');
 errPage.setRedirect(true);
 return errPage; 
}
return null; 
} 


 



Message Edited by arasu on 09-02-2008 04:59 PM
jwetzlerjwetzler
ah, yeah.  So you can either create just a dummy page that either redirects you to your special VF page or the error page, and you set THAT as your override page.  Or you can take a look at this example (there's a discussion on the forums somewhere but I could not find it quickly) and see if this helps you.  Looks like you were on the right track with your initial attempt at the action attribute.

Code:
<apex:page action="{!if($Profile.Name != ’System Administrator’, null, urlFor($Action.Account.Tab, $ObjectType.Account, null, true))}"
 standardController="Account">
  <!-- Replace the following with your custom Visualforce markup -->
  This page replaces your Account home page for all users except Administrators.
</apex:page>

This keeps you on the same page if you're not a sysadmin, but redirects you to the regular account overview page if you are.
jeffdonthemicjeffdonthemic

Was wondering if anyone has solved this issue and could post some solution code? I'm having the same problem with an infinite loop for the standard edit pages.

I have a Visualforce page which loads a controller that inspects the recordtype and forwards the user to specific Visualforce page based upon the value. If the record doesn't match the specific criteria they are redirected to the standard edit page. However, the user never makes it there as they are stuck in an infinite loop.

Any help would be greatly appreciated.

Thanks... Jeff

dchasmandchasman
You should use urlFor() to construct your target url and leverage the documented noOverride argument (specify true as its value) otherwise you are telling the system to attempt to navigate to the overridden page again.


Message Edited by dchasman on 09-17-2008 07:37 PM
jeffdonthemicjeffdonthemic
Doug,

Thanks for the help but how do you call URLFOR from Apex? Don't think that is allowed?

<apex:page standardController="Contact"
    extensions="dispatcherContactEditController"
    action="{!redir}"/>


public class dispatcherContactEditController {
   
    private ApexPages.StandardController controller;
   
    public dispatcherContactEditController(ApexPages.StandardController controller) {
        this.controller = controller;
    }    
     
    public PageReference redir() {

        PageReference newPage;
        Contact c = [Select id, recordtypeid From Contact Where Id = :ApexPages.currentPage().getParameters().get('id')];

        // visualforce page 1
        if (c.recordtypeid == '00000000') {
            newPage = new PageReference('/apex/Contact_Edit1?id='+ApexPages.currentPage().getParameters().get('id'));   
            newPage.setRedirect(true);
            return newPage;    
   
        // visualforce page 2
        } else if (c.recordtypeid == '11111111') {
            newPage = new PageReference('/apex/Contact_Edit2?id='+ApexPages.currentPage().getParameters().get('id'));   
            newPage.setRedirect(true);
            return newPage;        
       
        // go to the standard edit page
        } else {
            newPage = new PageReference(URLFOR($Action.Contact.Edit, ApexPages.currentPage().getParameters().get('id'), null, true));   
            newPage.setRedirect(true);
            return newPage;
        }
       
    }
   
}
dchasmandchasman
You are correct that urlFor() is not currently available in apex but you can combine VF expressions and apex code (might not even need apex code in this case) to accomplish your goal. Also, i have cleaned up a couple of things in your controller extension (e.g. leveraged the Page collection instead of hard coding string refs to pages):

Code:
<apex:page standardController="Contact" extensions="dispatcherContactEditController" 
action="{!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))}">
</apex:page>

public class dispatcherContactEditController {
public dispatcherContactEditController(ApexPages.StandardController controller) {
this.controller = controller;
}

public PageReference getRedir() {
PageReference newPage = null;
Contact c = (Contact)controller.getRecord();

if (c.recordtypeid == '00000000') {
newPage = Page.Contact_Edit1;
} else if (c.recordtypeid == '11111111') {
newPage = Page.Contact_Edit2;
}

if (newPage != null) {
newPage.getParameters().put('id', c.id);
}

return newPage;
}

private final ApexPages.StandardController controller;
}

 Depending on your page you may need to add a non displaying reference into your markup to let the standard controller know about the reference to contact.recordTypeId in your action method - something like this anywhere in your page should work:

Code:
<apex:outputText value="{!contact.recordTypeId}" rendered="false"/>

 and for a totally apex code free solution:

Code:
{!urlFor(case(contact.recordTypeId, '012300000004pYzAAI', $Page.contact_edit1, '11111111', $Page.contact_edit2, $Action.Contact.Edit), contact.id, [id = contact.id], true)}




Message Edited by dchasman on 09-19-2008 04:52 PM

Message Edited by dchasman on 09-19-2008 05:44 PM
This was selected as the best answer
jeffdonthemicjeffdonthemic
Doug,

Thanks for the help. The controller seems fine but I get the following error when trying to save the Visualforce page.

Code:
<apex:page standardController="Contact" extensions="dispatcherContactEditController" 
    action="{!nullValue(routeTo.url, urlFor($Action.Contact.Edit, contact.id, null, true))}">
    
    <apex:outputText value="contact.recordTypeId" rendered="false"/>
    
</apex:page>

Save error: Unknown property 'ContactStandardController.routeTo'. I tried to google routeTo.url but found nothing.

Thanks
Jeff Douglas
 

dchasmandchasman
Cut and paste error trying to work my simplified example back into your actual case - just corrected it. Also see the completely apex code free solution I just added  :-)
jeffdonthemicjeffdonthemic
Doug,

We are getting closer. Contacts that do not match the recordtypes are sent correctly to the standard edit page. However, the other two recordtypes are returning a blank pages.

I put a debug statement in each of the branches and they are reaching those points properly but it looks like it is not being redirected to the correct VF page. I tried adding newPage.setRedirect(true) but that didn't help.

The Page Editor clearly shows that the blank page being displayed is the Dispatcher_Contact_Edit page.

Here is the log:

17:27:12 DEBUG - ***Begining Page Log for /apex/Dispatcher_Contact_Edit

Element j_id0 called method {!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))} returned type String:/apex/contact_edit1?id=XXXXXXXXXXXXXXXXXX20080919212712.069:External entry point: returning from end of method public dispatcherContactEditController<Constructor>(ApexPages.StandardController) in 1 ms
20080919212712.069:Class.dispatcherContactEditController.getRedir: line 10, column 21: SOQL query with 1 row finished in 5 ms
20080919212712.069:Class.dispatcherContactEditController.getRedir: line 16, column 13: ====> Redirecting to Contact_Edit1
20080919212712.069:External entry point: returning System.PageReference from method public System.PageReference getRedir() in 6 ms

Thanks!
Jeff Douglas
dchasmandchasman
**bleep** - sorry about the runaround on this - there is a bug in the current release (I was using the new release while trying things out  - doh) that has been fixed in Winter '09 (fix is not in the initial release to Sandbox BTW - will be in the first production patch) that deals with auto redirecting in certain conditions that is keeping this from working. So for now the best I think we can do is:

Code:
public class dispatcherContactEditController {
public dispatcherContactEditController(ApexPages.StandardController controller) {
this.controller = controller;
}

public PageReference redir() {
Contact c = (Contact)controller.getRecord();

PageReference newPage;
if (c.recordtypeid == '0000000000') {
newPage = Page.Contact_Edit1;
} else if (c.recordtypeid == '11111111') {
newPage = Page.Contact_Edit2;
} 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;
}



Message Edited by dchasman on 09-19-2008 07:12 PM

Message Edited by dchasman on 09-26-2008 07:41 AM
michaellatideasmichaellatideas
I'm trying to do a similar thing as described in this post with a custom object -- but when I'm saving a VisualForce page I'm getting an error message of

Error: Incorrect parameter for function nullValue(). Expected Object, received Text

I can't find the documentation for the nullValue function, so I'm not quite sure what I've got wrong here, as I think I've been following along with the discussion.


And my VisualForce page is this...

<apex:page standardController="MPR__c" extensions="MPRControllerExtension" tabStyle="MPR__c" 
    action="{!nullValue(redir.url, urlFor($Action.MPR__c.Edit, MPR__c.id, null, true))}">
   
    <apex:outputText value="{!MPR__c.recordTypeId}" rendered="false"/>
</apex:page>


What am I missing?

My getredir fuction has the same signature as above...

michaellatideasmichaellatideas
> What am I missing?

Besides obviously not catching for smileys when I cut and paste text...

michaellatideasmichaellatideas
I was able to completely resolve it -- though I needed three visual force pages for my use case.  I'm only overriding the new behavior, not the edit behavior.

the controller on VFPage1 determines which new record type we're using. 

It redirects to VFPage2 if we want to use the standard "new record" page, and passes along all of the the parameters. 
It redirects to VFPage3 if we want to use the record type that we want the custom Visual Force Edit Page.

And VFPage2 is the one that immediately redirects to the standard screen using URLFOR as described above.

Thanks for the thread here...
jeffdonthemicjeffdonthemic
Thanks for all the help Doug. It looks like the patch on the sandbox did the trick. My code is working and I just wanted to follow up with the post of my code in case someone else needs it:

Controller

Code:
public class dispatchController {
 
    public dispatchController(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 == '1111111111') {
            newPage = Page.Contact_Edit1;
            
        } else if (c.recordtypeid == '2222222222') {
            newPage = Page.Contact_Edit2;
            
        } 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;   
}

 Visualforce Page

Code:
<apex:page standardController="Contact" extensions="dispatchController" 
    action="{!nullValue(redir.url, urlFor($Action.Contact.Edit, contact.id, null, true))}">
</apex:page>

You can then override the Edit button with this Visualforce page and everyone will be happy.

Jeff Douglas
Informa plc

michaellatideasmichaellatideas
I'm still having some challenges here doing this for mine, where it is new buttons instead of edit buttons.

As I described earlier, I'd like to have one record type go to a custom new page, but all of the other record types go to their standard record types.

My problem right now is that it successfully goes to the correct page when it's the custom record type, but I'm having problems getting the standard page to work right. 

Right now, the flow for a "standard" new page is this:

 Record Type Selection Screen -> PAGE2 -> Record Type Selection Screen -> Standard Edit Screen

So basically, what I'm seeing is that it's going back to the record type selection screen a second time.

My PAGE2 has this:

<apex:page standardController="MPR__c" extensions="MPRFulfillmentController" tabStyle="MPR__c" 
    action="{!urlFor($Action.MPR__c.New, MPR__c.id, NULL, true)}">

And it looks like that's redirecting it to the record type selection screen -- but I want to have it redirect to the entry screen for that record type. 

I'm not quite sure what I'm missing here, and I'm open to suggestions.
jeffdonthemicjeffdonthemic
Could you post your controller's code?
michaellatideasmichaellatideas
Certainly.  The relevant pages and controller code:

MPR: (this is the page the new button points to)
<apex:page standardController="MPR__c" extensions="MPRFulfillmentController" tabStyle="MPR__c"  
    action="{!getRedir}">
    <apex:outputText value="{!MPR__c.recordTypeId}" rendered="false"/>
    <apex:outputText value="{!MPR__c.id}" rendered="false"/>

</apex:page>

 
mpr2:
<apex:page standardController="MPR__c" extensions="MPRFulfillmentController" tabStyle="MPR__c"  

    action="{!urlFor($Action.MPR__c.New, MPR__c.id, NULL, true)}">
    <apex:outputText value="{!MPR__c.recordTypeId}" rendered="false"/>
    <apex:outputText value="{!MPR__c.id}" rendered="false"/>
</apex:page>

 
Controller snippet:
    public PageReference getRedir() {

        RecordType r = [select id, Name from RecordType where Name = :rid];
        
        PageReference newPage;
        
        Id id = System.currentPageReference().getParameters().get('RecordType');
        
        if (mpr.recordtypeid == r.id) {
            newPage = Page.mprfulfillment1;
            newPage.getParameters().put('id', mpr.id);
        } else if ( id == r.id ) {
            newPage = Page.mprfulfillment1;
            mpr.recordtypeid = r.id;
            newPage.getParameters().put('id', mpr.id);
        } else {
            newPage = Page.mpr2; 
            mpr.recordtypeid = id;
            newPage.getParameters().put('id', mpr.id);
            newPage.getParameters().put('RecordType', id);                 
        }

        return newPage.setRedirect(true);
    }

 It's the "else" branch that I don't have right yet....


jeffdonthemicjeffdonthemic
I'm working with our tech support rep right now on a very similar issue and I'll post the code when it is complete. I can successfully route the pages but am having a different issue.

In the meantime, you might tweak your controller to simply return null when all of the condition are not met and you want to return the user to the standard new page. This is working for me.

Good luck.

Jeff Douglas
Informa Plc
michaellatideasmichaellatideas
I'm working with my tech support rep on this as well, so I suspect we're on parallel paths. 

I tried to return 'null' on the 'else' path, and all that does for me is bring up a blank page.
michaellatideasmichaellatideas
I'm still struggling to get this right, but I've added something to the Idea Exchange that is relevant to this:

http://ideas.salesforce.com/article/show/10093972/Assign_Visual_Force_Pages_like_a_Page_Layout
MerialMerial
Hi,

I'm also desperate with yhis issue, using s-controls is not a good idea for VF pages, and using the extension makes the code in the custom controller just not work. I'll be following this thread and also looking for solutions.

Voted for the idea!

thanks,
jeffdonthemicjeffdonthemic
I have posted a working solution to this at my blog. We are currently using this code in our production environment.
 
Please see the link below
 
 
 
Jeff Douglas
Informa Plc
michaellatideasmichaellatideas
Awesome.  Thanks, I'll try that out.
sofogabesofogabe

I've got this almost working, except when you choose the record type that directs to the standard page, it returns you to the record selection page, and you have to select the same record type a second time (and sometimes even a third) to get it to finally direct to the standard page.

 

Any thoughts?

Thanks.

rubixtiousrubixtious
I have the same issue (redirecting to the record type selection page twice).  Has anyone got this working correctly?
Mitesh SuraMitesh Sura
Thanks all. For me just one line of code did the trick. I had to do some digging, but eventually it worked!

<apex:page standardController="QuoteLineItem" >

	<br/>
	Redirecting...
	<br/>
	<apex:outputField value="{!QuoteLineItem.id}" rendered="false"/>
	<apex:outputField value="{!QuoteLineItem.Quoteid}" rendered="false"/>rendered="false"/>
	
	<script>
	    var quoteId = '{!JSINHTMLENCODE(QuoteLineItem.QuoteId)}';
	    var itemId = '{!JSINHTMLENCODE(QuoteLineItem.id)}';
	    
	    //Check condition
	    if(true){
        	alert('Sorry cannot do that!');
	        window.top.location='/' +quoteId; 
       	    }
	    else
       		window.top.location='{!URLFOR($Action.QuoteLineItem.Edit, QuoteLineItem.id, ['retURL'='/'+QuoteLineItem.QuoteId], true)}';
	</script>


</apex:page>