function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Greg RohmanGreg Rohman 

Assistance with functional custom-controller Visualforce page conversion to standard controller

Hello.

Our organization doesn't want our sales reps to see the leads of other reps... but they do want the reps the ability to just check and see if a lead exists in the system before they can enter it in themselves, to prevent competition.

I wasn't able to accomplish this with the Sharing Settings in the UI. I did put together a trigger that, upon actual entering of the lead, it will prevent the lead from being entered if a lead with the same email address already exists. But, they want the reps to be able to do a quick search and see if the lead exists (and what rep it belongs to) before they enter in all of the additional Lead information.

I put together a Visualforce page that has three fields: Last Name, Company, and Email, and will issue a SOQL query to see if any Leads exist that match those values. It will then display the Lead name, company, email and owner to the rep so they know not to enter it themselves (I plan to update the trigger to prevent entry as well). If it doesn't exist, a link will be provided to go ahead and finish entering the Lead details, picking up the last name, company, and email address that they already put in.

This page is basically functional at this point. It needs some tweaking and CSS, but it's working. I'm new to Visualforce, and when I attempted to actually override the "New" button on the Lead tab, I learned that I can only override that button with a Visualforce page that uses the standard Lead controller.

The code for the page and the class is below. Any help would be very much appreciated.

Page:
Code:
<apex:page controller="ProspectDupeSearch" tabStyle="Lead">
    <apex:form >
        <apex:pageBlock title="Prospect Duplicate Search">
                <strong>Enter the last name, company, and/or email address for a new prospect you are looking to add.</strong>
                <br/><br/>
                Last Name<br /><apex:inputText id="searchName" value="{!searchName}"/>
                <br/><br/>
                Company<br /><apex:inputText id="searchCompany" value="{!searchCompany}"/>
                <br/><br/>
                Email<br /><apex:inputText id="searchEmail" value="{!searchEmail}"/>
                <br/><br/>
                <apex:commandButton value="Check for Duplicates" action="{!doSearch}" rerender="resultPanel"/>
        </apex:pageBlock>

        <apex:pageBlock title="Search Results">
            <apex:outputPanel id="resultPanel" layout="block">
                <apex:outputLink value="/00Q/e—name_lastlea2={!searchName}&lea3={!searchCompany}&lea11={!searchEmail}&retURL=%2F00Q%2Fo">Create new Prospect</apex:outputLink> 
                <apex:dataTable value="{!results}" var="r" cellPadding="4" border="1">
                    <apex:column >{!r.Name}</apex:column>
                    <apex:column >{!r.Company}</apex:column>
                    <apex:column >{!r.Email}</apex:column>
                    <apex:column >{!r.Owner.Name}</apex:column>
                </apex:dataTable>

                <apex:outputText id="sOutput" value="{!results}"/>
            </apex:outputPanel>
        </apex:pageBlock>
   
    </apex:form>
</apex:page>

Class:
Code:
public class ProspectDupeSearch {

    String searchName;
    String searchCompany;
    String searchEmail;
    List<Lead> results;

    public String getSearchName() { return searchName; }
    public void setSearchName(String s) { searchName = s; }

    public String getSearchCompany() { return searchCompany; }
    public void setSearchCompany(String s) { searchCompany = s; }
    
    public String getSearchEmail() { return searchEmail; }
    public void setSearchEmail(String s) { searchEmail = s; }
    
    // Return info
    public List<Lead> getResults() { return results; }

    public PageReference doSearch() {
        String queryString = 'SELECT Id,Name,Company,Email,Owner.Name FROM Lead WHERE IsConverted=False';
        queryString = queryString + ' AND Lead.Name LIKE \'%' + String.escapeSingleQuotes(searchName) + '%\'';
        queryString = queryString + ' AND Lead.Company LIKE \'%' + String.escapeSingleQuotes(searchCompany) + '%\'';
        queryString = queryString + ' AND Lead.Email LIKE \'%' + String.escapeSingleQuotes(searchEmail) + '%\'';
        queryString = queryString + ' ORDER BY LastName ASC';
        results = Database.query(queryString);
        return null;
    }
}


Thanks in advance.

-Greg

 

Best Answer chosen by Admin (Salesforce Developers) 
JeremyKraybillJeremyKraybill
Hi there Greg,

this is one of the somewhat underdocumented features of VisualForce, but once you figure out how it works it is straight forward.

To convert a page to use a standard controller, you need to do two things. First, your page tag needs to specify the base controller, and then point to your controller as an "extension". Here's an example using opportunity:

Code:
<apex:page standardController="Opportunity" extensions="MyOpportunityRelatedController">

 Then you need to add a special constructor to your controller that will be invoked instead of the normal default constructor.
Code:
public MyOpportunityRelatedController(ApexPages.StandardController myController) {
[your constructor code here]
}

 Those two things will cause that page to be selectable on the page selector for the detail page. Note that one of the nice things about this is that you can use "myController.getRecord()" to get the active record -- you don't need "Id" parameters at the page level.

Also, if you want your page to be linkable to a custom button on the list page (rather than the detail page), which gives you the ability to perform controller logic on every record the user clicks a checkbox next to, you use this constructor instead:
Code:
public MyOpportunityRelatedController (ApexPages.StandardSetController stdController) {
 List<Opportunity> userSelections = (List<Opportunity>) stdController.getSelected();
 [other constructor code here]
}

It is a little "magical", but SF knows based on these constructor signatures that your pages can be used as detail pages or list view pages.

HTH

Jeremy Kraybill
Austin, TX

All Answers

JeremyKraybillJeremyKraybill
Hi there Greg,

this is one of the somewhat underdocumented features of VisualForce, but once you figure out how it works it is straight forward.

To convert a page to use a standard controller, you need to do two things. First, your page tag needs to specify the base controller, and then point to your controller as an "extension". Here's an example using opportunity:

Code:
<apex:page standardController="Opportunity" extensions="MyOpportunityRelatedController">

 Then you need to add a special constructor to your controller that will be invoked instead of the normal default constructor.
Code:
public MyOpportunityRelatedController(ApexPages.StandardController myController) {
[your constructor code here]
}

 Those two things will cause that page to be selectable on the page selector for the detail page. Note that one of the nice things about this is that you can use "myController.getRecord()" to get the active record -- you don't need "Id" parameters at the page level.

Also, if you want your page to be linkable to a custom button on the list page (rather than the detail page), which gives you the ability to perform controller logic on every record the user clicks a checkbox next to, you use this constructor instead:
Code:
public MyOpportunityRelatedController (ApexPages.StandardSetController stdController) {
 List<Opportunity> userSelections = (List<Opportunity>) stdController.getSelected();
 [other constructor code here]
}

It is a little "magical", but SF knows based on these constructor signatures that your pages can be used as detail pages or list view pages.

HTH

Jeremy Kraybill
Austin, TX

This was selected as the best answer
Greg RohmanGreg Rohman
Hi Jeremy.

Thank you for the response. I'm not 100% clear as to where I add the Apex code. I changed the top of my class to the following, and it seems to work, but I don't quite understand how or why, nor if it's the correct way:

Code:
public class ProspectDupeSearch {

public ProspectDupeSearch(ApexPages.StandardController myController) {
}

[rest of existing code here]

My second question that perhaps you can help me with. I was able to override the "New" button for leads, but now, in my new page, the code I have to have the salesperson continue to enter the lead isn't working. The "New" button override is overriding this link too, essentially leaving them in a loop:

Code:
<apex:outputLink value="/00Q/e—name_lastlea2={!searchName}&lea3={!searchCompany}&lea11={!searchEmail}&retURL=%2F00Q%2Fo">Create new Prospect</apex:outputLink> 

Is there some way to have them continue to the existing Add Lead page from the Visualforce page?

-Greg


 

JeremyKraybillJeremyKraybill
I am not sure I understand the problem you are facing -- can you describe more detail about the "loop" behavior you are seeing (which page transitions / buttons are involved) and exactly what you are trying to accomplish?
Greg RohmanGreg Rohman
Hi Jeremy.

Our sharing model prevents the sales team from seeing Leads owned by other salespeople. But, to help avoid lead duplicate entry, we wanted a way to allow them to quickly check and see if the lead existed in the system before they actually fill in all of the information and attempted to save the lead (otherwise I can accomplish it with a trigger).

I built this page that overrides the "New" button for leads and allows them to enter the last name, company and email address of a potential new lead, and the page will search the Lead database and return any matching results, if any. If no matches are found, I want to provide a link to continue to enter the new lead at the standard lead entry screen, with the last name, company and email already provided. that link line is below:

Code:
<apex:outputLink value="/00Q/e—name_lastlea2={!searchName}&lea3={!searchCompany}&lea11={!searchEmail}&retURL=%2F00Q%2Fo">Create new Prospect</apex:outputLink>


Since I've overridden the "New" functionality, though, the link is also being overridden, so when it's clicked, it just takes them back to this same Visualforce page that I've created. How can I provide a link to the actual Lead entry screen?

Thanks.

-Greg



JeremyKraybillJeremyKraybill
Aha, yes, SF will take the "override" as also overriding the edit URL for the page. Afraid this isn't an area I have much experience with, but the standard controller you are overriding has an edit() method which returns a PageReference to the standard edit page. You would do something like this

Code:
private ApexPages.StandardController ctl;

public MyController(ApexPages.StandardController myController) {
  ctl = myController;
}

public PageReference userActionToNewPage() {
  PageReference ret = ctl.edit();
  ret.getParameters().put('somekey', 'somevalue');
  return ret;
}

 
Again not 100% sure since I haven't had to do this, but I would think controller.edit() would still return the right edit page even with your override.

HTH

Jeremy Kraybill
Austin, TX
dchasmandchasman
Jeremy is spot on - and overrides are something that is not implemented via url rewritting rather we took a server side forwarding based approach so it does not matter how the url is obtained it will always go to the override target (there is a query param and argument to urlFor() that can keep the override from being applied).
sf.dev.ax1103sf.dev.ax1103

Hi Greg,

 

         Can you please post your code.I am having the similar issue of converting custom controller to standard controller and also were you able to solve this new record link issue that you are having ?

 

Thanks