+ Start a Discussion
michaelforcemichaelforce 

URL Parameters Randomly Null in Controller Extension Constructor

I have overridden the "new" and "edit" buttons for a custom object with a Visualforce page / Apex extension.  The constructor of the extension gets the "retURL" parameter from the currentPage().getParameters() like so:

 

 

theOpp = [select Id, Name, (select Id, Account__c, Opportunity__c, Role__c from Partners2__r) from Opportunity where Id = :ApexPages.currentPage().getParameters().get('retURL').substring(1) limit 1];

 

 

I have confirmed that all buttons available to our users to get to this screen always contain /OPPORTUNITYID as the retURL and thus I am just removing the slash and using the Id to query an Opportunity.

 

The problem is that it is randomly producing errors... stating the retURL parameter is null.  Then the same user can go back and try again and it works... totally sporadic.  So I am thinking maybe the constructor is running "too quickly" so the parameter isn't established yet?  Possibly I need to make this call in the "Action" of the page instead?  Any help is appreciated!

Best Answer chosen by Admin (Salesforce Developers) 
rtuttlertuttle

Michael,

 

I'm wondering if you're trying to override the new button on a related list?  From the description and code sample I'm taking a guess you're overriding some custom object that relates to opportunity right?

 

If so I'm wondering if the standardcontroller automatically passes the opportunity id into the new custom object (as part of the relation).  (Tested and it does)

 

If this is your use case you can just reference the opportunity id that was passed as part of the lkid automatically to your standard controller and filled into your lookup field.  In my case the lookup field was Opportunity__c and I was able to reference it on the page.  You should be able to access it from the extension like so:

 

 

public oppPropTest(ApexPages.StandardController controller) {
    String oppId = (String)controller.getRecord().get('Opportunity__c');
    // your query with the opp id goes here
}

 

 

 

Demo code for finding this info:

 

extension:

 

public with sharing class oppPropTest {
    public oppPropTest(ApexPages.StandardController controller) {
        this.controller = controller;
        for(String i : ApexPages.currentPage().getParameters().keySet()) {
            testOutput.add(i + ': ' + ApexPages.currentPage().getParameters().get(i));
        }
    }
    private ApexPages.StandardController controller;
    public List<String> testOutput {
        get {
            if(testOutput == null) testOutput = new List<String>();
            return testOutput;
        }
        set;
    }
    
}

 

 

 

Page:

<apex:page standardController="OppTest__c" extensions="oppPropTest">
    <apex:repeat value="{!testOutput}" var="prop">
        {!prop}<br/>
    </apex:repeat>
    <br/><br/>
    {!OppTest__c.Opportunity__c}
</apex:page>

 

 

-Richard

All Answers

mtbclimbermtbclimber

I presume you are referring to the retURL param salesforce sets. Recognize this isn't technically a supported API.

 

That being said are you sure there are no avenues whereby the param isn't set (aside from a user going straight to the edit link by typing it in)?  Is this a master/detail child of opportunity and is there no tab for this object, and is there no visualforce page that generates a link to the form, etc?

 

Do you have any reproducible case? Perhaps you can dump the url off of the current page to the log when it's null?  We can look at it but, again, recognize that you're dealing with an unsupported API.

 

To your question there shouldn't be any portion of the lifecycle within your controller extension where this is null when a value was actually provided to the request - including the constructor.

rtuttlertuttle

Michael,

 

I'm wondering if you're trying to override the new button on a related list?  From the description and code sample I'm taking a guess you're overriding some custom object that relates to opportunity right?

 

If so I'm wondering if the standardcontroller automatically passes the opportunity id into the new custom object (as part of the relation).  (Tested and it does)

 

If this is your use case you can just reference the opportunity id that was passed as part of the lkid automatically to your standard controller and filled into your lookup field.  In my case the lookup field was Opportunity__c and I was able to reference it on the page.  You should be able to access it from the extension like so:

 

 

public oppPropTest(ApexPages.StandardController controller) {
    String oppId = (String)controller.getRecord().get('Opportunity__c');
    // your query with the opp id goes here
}

 

 

 

Demo code for finding this info:

 

extension:

 

public with sharing class oppPropTest {
    public oppPropTest(ApexPages.StandardController controller) {
        this.controller = controller;
        for(String i : ApexPages.currentPage().getParameters().keySet()) {
            testOutput.add(i + ': ' + ApexPages.currentPage().getParameters().get(i));
        }
    }
    private ApexPages.StandardController controller;
    public List<String> testOutput {
        get {
            if(testOutput == null) testOutput = new List<String>();
            return testOutput;
        }
        set;
    }
    
}

 

 

 

Page:

<apex:page standardController="OppTest__c" extensions="oppPropTest">
    <apex:repeat value="{!testOutput}" var="prop">
        {!prop}<br/>
    </apex:repeat>
    <br/><br/>
    {!OppTest__c.Opportunity__c}
</apex:page>

 

 

-Richard

This was selected as the best answer
michaelforcemichaelforce

rtuttle,

 

Thanks, that's awesome.  You are spot on... it is a Master-Detail Child object of the Opportunity Object and the custom entry screen is for when they click "New" on the related list... OR when they click "Edit" next to any record in the related list (doesn't matter which record... brings them to the same screen where they manage all).

 

You're code works perfectly for the "New" scenario (which is cool... I didn't think it would which is why I went the URL parameter route... I should have tried it!).  For the "Edit" scenario I simply added an if statement, because the Opportunity__c is not loaded initially just the Id of the child object so you have to query it like so:

 

 

String oppId;
        
if(controller.getId()==null){    //Runs when user clicks 'New'
    oppId = (String)controller.getRecord().get('Opportunity__c');
}
else{    //Runs when user clicks 'Edit'
    oppId = [select Id, Opportunity__c from Partners2__c where Id=:controller.getId() limit 1].Opportunity__c;
}

//Then use :oppId to query opp...

 

 

Thanks again, this is a great workaround for the mysterious URL problem...

 

 

Andrew,

 

It is still worth investigating the URL issue, and I have a little more information.  Out of 25 or so errors, a large majority where in southeast asia, eastern europe.  Then one in south america, south europe, and canada each.  None in the US (even though most of our users are here).  So basically places where our corporate network is the slowest is where the error was happening the most.  One user got back to me stating that they got the error when the network was being extra slow and they refreshed the screen (the visualforce page).  So perhaps there are certain browsers that may "lose" or "miss" certain URL parameters when you refresh when the page is still loading??

 

Luckily for now I have a workaround... but I'm curious about this because in the future I may not have any other way but to use URL parameters for a given page.

 

Thanks for the responses guys,

Michael

rtuttlertuttle

michael,

 

No problem, it was great meeting you at Dreamforce this year.  On edit this should still work if I'm not mistaken because a master detail requires the field to be filled in no?

 

 

 

-Richard (_drako @ twitter)

michaelforcemichaelforce

oh hey @drako!  haha

 

No, for existing records the controller only has the Id (and maybe any fields referenced in the page?) but in my case it threw an error saying I didn't query the requested field 'Opportunity__c'.

rtuttlertuttle

Nevermind, blonde moment.  A workaround to this is to add an invisible field to the visualforce page.  This causes the standardcontroller to query it and make it available in the extension.  Either way works but I tend to avoid forcing unnecessary queries.

 

Example (assuming your object is called object__c)

 

 

<apex:outputPanel rendered="{!false}">
<apex:outputField value="{!Object__c.Opportunity__c}"/>
</apex:outputPanel>

 

 

 

 

 

-Richard