Visualforce Development Cookbook

By Keir Bowden
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. General Utilities

About this book

Visualforce, in conjunction with Apex, makes it easy to develop sophisticated, custom UIs for Force.com desktop and mobile apps without having to write thousands of lines of code and markup. The "Dynamic Binding" feature of Visualforce lets you develop generic Visualforce pages to display information related to the records without necessarily knowing which data fields to show. This is accomplished through a formula-like syntax, which makes it simple to manage even a complex hierarchy of records.

"Visualforce Development Cookbook" provides solutions for a variety of challenges faced by Salesforce developers and demonstrates how easy it is to build rich, interactive pages using Visualforce. Whether you are looking to make a minor addition to the standard page functionality or override it completely, this book will provide you with the required help throughout.

"Visualforce Development Cookbook" starts with explaining the simple utilities and builds up to advanced techniques for data visualization and reuse of functionality. This book contains recipes that cover various topics like creating multiple records from a single page, visualizing data as charts, using JavaScript to enhance client-side functionality, building a public website and making data available to a mobile device.

"Visualforce Development Cookbook" provides lots of practical examples to enhance and extend the Salesforce user interface.

Publication date:
September 2013
Publisher
Packt
Pages
334
ISBN
9781782170808

 

Chapter 1. General Utilities

In this chapter, we will cover the following recipes:

  • Overriding standard buttons

  • Data-driven styling

  • Turning off an action poller

  • Visualforce in the sidebar

  • Passing parameters to action methods

  • Reacting to URL parameters

  • Passing parameters between Visualforce pages

  • Opening a pop-up window

  • Adding a launch page

  • Testing a custom controller

  • Testing a controller extension

 

Introduction


This chapter provides solutions for a variety of situations that Visualforce developers are likely to encounter on a regular basis. Enhancing or replacing standard functionality with Visualforce enriches the user experience, improving user productivity and adoption. Visualforce also allows business processes to be highly systemized, guiding users through the creation and the ongoing management of data. Writing effective tests for Visualforce controllers is a key skill that allows developers to deploy Visualforce pages to production, and be confident that they will work as intended.

 

Overriding standard buttons


Two common complaints from users are that the information they are interested in requires a number of clicks to access, or that there is too much information on a single page, resulting in a cluttered layout that requires significant scrolling. This is an area where a Visualforce override can make a significant difference by traversing relationships to display information from a number of records on a single page.

Salesforce allows the standard pages associated with sObject record actions, such as view and edit, to be overridden with Visualforce pages. This is typically used to display the record in a branded or customized format; for example, to display the details and related lists in separate tabs.

In this recipe, we will override the standard page associated with viewing an account record with a Visualforce page that not only provides a tabbed user interface, but also lifts up additional activity information from the related contact list and line item information from the related opportunity lists. Further, the related opportunities displayed will be limited to those which are open.

Note

Only Visualforce pages that use the standard controller for the sObject can override standard pages.

Getting ready

This recipe makes use of a standard controller, so we only need to create the Visualforce page.

How to do it…

  1. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  2. Click on the New button.

  3. Enter AccViewOverride in the Label field.

  4. Accept the default AccViewOverride that is automatically generated for the Name field.

  5. Paste the contents of the AccViewOverride.page file from the code download into the Visualforce Markup area and click on the Save button.

  6. Then, navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  7. Locate the entry for the AccViewOverride page and click on the Security link.

  8. On the resulting page, select which profiles should have access and click on the Save button.

    Note

    As the record view override applies to all users, ensure that all profiles are given access to the Visualforce page. Any user with a profile that does not have access will receive an Insufficient Privileges error when attempting to view an account record.

  9. Now that the Visualforce page is complete, configure the account view override. Navigate to Your Name | Setup | Customize | Accounts | Buttons, Links and Actions.

  10. Locate the View entry on the resulting page and click on the Edit link.

  11. On the following page, locate the Override With entry, check the Visualforce Page radio button, and choose AccViewOverride from the list of available pages.

  12. Click on the Save button.

How it works…

When a user clicks on an account record link anywhere in Salesforce, the tabbed page with details from related records is displayed, as shown in the following screenshot:

The key areas of the code are the tabs for the related records. The Open Opportunities tab iterates the opportunities related list, and generates an <apex:pageblock /> for each opportunity that is currently open by encapsulating this inside a conditionally rendered <apex:outputPanel />.

<apex:repeat value="{!Account.Opportunities}" var="opp">
  <apex:outputPanel rendered="{!NOT(opp.IsClosed)}">
    <apex:pageBlock title="{!opp.Name}">

Then, the standard <apex:relatedList /> component is used to generate the opportunity product list by specifying the current value of the opportunity iterator as the subject of the component.

 <apex:relatedList subject="{!opp}" list="OpportunityLineItems" />
 

Data-driven styling


A useful technique when creating a custom user interface with Visualforce is to conditionally style important pieces of information to draw the user's attention to them as soon as a page is rendered.

Most Visualforce developers are familiar with using merge fields to provide sObject field values to output tags, or to decide if a section of a page should be rendered. In the tag shown below, the merge field, {!account.Name}, will be replaced with the contents of the name field from the account sObject:

<apex:outputField value="{!account.Name}"/>

Merge fields can also contain formula operators and be used to dynamically style data when it is displayed.

In this recipe we will display a table of campaign records and style the campaign cost in green if it was within budget, or red if it was over budget.

How to do it…

  1. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  2. Click on the New button.

  3. Enter ConditionalColour in the Label field.

  4. Accept the default ConditionalColour that is automatically generated for the Name field.

  5. Paste the contents of the ConditionalColour.page file from the code download into the Visualforce Markup area and click on the Save button.

  6. Click on the Save button to save the page.

  7. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  8. Locate the entry for the ConditionalColour page and click on the Security link.

  9. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser displays the ConditionalColour page: https://<instance>/apex/ConditionalColour. Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

A list of campaigns is displayed, with the campaign cost rendered in red or green depending on whether it came in on or over budget.

Conditional styling is applied to the Actual Cost column by comparing the actual cost with the budgeted cost.

<apex:column style="color:
   {!IF(AND(NOT(ISNULL(campaign.ActualCost)), 
   campaign.ActualCost<=campaign.BudgetedCost), 
  "lawngreen", "red")}" value="{!campaign.ActualCost}"/>

See also

  • The Data-driven decimal places recipe in Chapter 2, Custom Components shows how to format numeric values to a specified number of decimal places.

 

Turning off an action poller


The standard Visualforce <apex:actionPoller/> component sends AJAX requests to the server based on the specified time interval. An example use case is a countdown timer that sends the user to another page when the timer expires. But what if the action poller should stop when a condition in the controller becomes true, for example, when a batch apex job completes or an update is received from a third-party system?

In this recipe, we will simulate the progression of a payment through a number of states. An action poller will be used to retrieve the latest state from the server and display it to the user. Once the payment reaches the state Complete, the action poller will be disabled.

Getting ready

This recipe makes use of a custom controller, so this will need to be created before the Visualforce page.

How to do it…

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the PollerController.cls Apex class from the code download into the Apex Class area.

    Tip

    Note that there is nowhere to specify a name for the class when creating through the setup pages; the class name is derived from the Apex code.

  4. Click on the Save button.

  5. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  6. Click on the New button.

  7. Enter ActionPoller in the Label field.

  8. Accept the default ActionPoller that is automatically generated for the Name field.

  9. Paste the contents of the ActionPoller.page file from the code download into the Visualforce Markup area.

  10. Click on the Save button to save the page.

  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  12. Locate the entry for the ActionPoller page and click on the Security link.

  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser displays the ActionPoller page: https://<instance>/apex/ActionPoller.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

The page polls the server for the current state, displaying the message Polling … when the action poller executes as shown in the following screenshot:

Once the current state reaches Complete, the action poller terminates.

The key to this recipe is the enabled attribute on the actionPoller component.

<apex:actionPoller action="{!movePayment}" 
     rerender="payment" interval="5" status="status" 
     enabled="{!paymentState!='Complete'}"/>

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

This merge field references the paymentState property from the custom controller, which is evaluated each time the action poller executes until it becomes false. At this time the action poller is permanently disabled.

The Polling … message is generated by the actionStatus component associated with the action poller. This component has a startText attribute but not a stopText attribute, which means that the text will only be displayed while the AJAX request is in progress.

<apex:actionStatus startText="Polling ..." id="status"/>

See also

  • The Using action functions recipe in Chapter 7, JavaScript shows how to execute a controller.

 

Visualforce in the sidebar


Visualforce is commonly used to produce custom pages that override or supplement standard platform functionality. Visualforce pages can also be incorporated into any HTML markup through use of an iframe.

Note

An iframe, or inline frame, nests an HTML document inside another HTML document. For more information, visit http://reference.sitepoint.com/html/iframe.

In this recipe, we will add a Visualforce page to a Salesforce sidebar component. This page will display the number of currently open cases in the organization, and will be styled and sized to fit seamlessly into the sidebar.

Getting ready

This recipe makes use of a custom controller, so this will need to be created before the Visualforce page.

How to do it…

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the CasesSidebarController.cls Apex class from the code download into the Apex Class area.

  4. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  5. Click on the New button.

  6. Enter CasesSidebar in the Label field.

  7. Accept the default CasesSidebar that is automatically generated for the Name field.

  8. Paste the contents of the CasesSidebar.page file from the code download into the Visualforce Markup area.

  9. Click on the Save button to save the page.

  10. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  11. Locate the entry for the CasesSidebar page and click on the Security link.

  12. On the resulting page, select which profiles should have access and click on the Save button.

    Note

    Ensure that all profiles whose sidebar will display the Visualforce page are given access. Any user with a profile that does not have access will see an Insufficient Privileges error in their sidebar.

  13. Next, create the home page component by navigating to the Home Page Components setup page by clicking on Your Name | Setup | Customize | Home | Home Page Components.

  14. Scroll down to the Custom Components section and click on the New button.

  15. If the Understanding Custom Components information screen appears, as shown in the following screenshot, click on the Next button.

    Tip

    To stop this information screen appearing each time you create a home page component, select the Don't show this page again box before clicking on the Next button.

  16. On the next page, Step 1. New Custom Components, enter Case Count by Status in the Name field, select the HTML Area option, and click on the Next button.

  17. On the next page, Step 2. New Custom Components, select the Narrow (Left) Column option.

  18. Select the Show HTML box.

  19. Paste the following markup into the editable area:

    <iframe style="border: none" src="/apex/CasesSidebar"  seamless=""></iframe>
  20. Click on the Save button.

  21. Next, add the new component to one or more home page layouts. Navigate to Your Name | Setup | Customize | Home | Home Page Layouts.

  22. Locate the name of the home page layout you wish to add the component to and click on the Edit link.

  23. On the resulting page, Step 1. Select the Components to show, select the Case Count by Status box in the Select Narrow Components to Show section and click on the Next button.

  24. On the next page, Step 2. Order the Components, use the arrow buttons to move the Case Count by Status component to the desired position in the Narrow (Left) Column list and click on the Save button.

  25. Repeat steps 22 to 24 for any other home page layouts that will contain the sidebar component.

    Tip

    This will add the component to the sidebar of the home page only. To add it to the sidebar of all pages, a change must be made to the user interface settings.

  26. Navigate to Your Name | Setup | Customize | User Interface and locate the Sidebar section.

  27. Select the Show Custom Sidebar Components on All Pages box as shown in the following screenshot, and click on the Save button.

How it works…

The component appears in the sidebar on all pages, showing the number of cases open for each nonclosed status, as shown in the following screenshot:

There's more…

The case counts displayed in the sidebar will be retrieved when the page is displayed, but will remain static from that point. An action poller can be used to automatically refresh the counts at regular intervals. However, this will introduce a security risk, as each time the poller retrieves the updated information it will refresh the user's session. This means that if a user were to leave their workstation unattended, the Salesforce session will never expire. If this mechanism is used, it is important to remind users of the importance of locking their workstation should they leave it unattended.

 

Passing parameters to action methods


When developers move to Apex/Visualforce from traditional programming languages, such as Java or C#, a concept many struggle with is how to pass parameters from a Visualforce page to a controller action method.

Passing parameters to an action method is key when a Visualforce page allows a user to manage a list of records and carry out actions on specific records. Without this, the action method cannot determine which record to apply the action to.

In this recipe, we will output a list of opportunities and for each open opportunity, provide a button to update the opportunity status to Closed Won. This button will invoke an action method to remove the list element and will also send a parameter to the controller to identify which opportunity to update.

Getting ready

This recipe makes use of a custom controller, so this will need to be created before the Visualforce page.

How to do it…

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the ActionParameterController.cls Apex class from the code download into the Apex Class area.

  4. Click on the Save button.

  5. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  6. Click on the New button.

  7. Enter ActionParameter in the Label field.

  8. Accept the default ActionParameter that is automatically generated for the Name field.

  9. Paste the contents of the ActionParameter.page file from the code download into the Visualforce Markup area.

  10. Click on the Save button to save the page.

  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  12. Locate the entry for the ActionParameter page and click on the Security link.

  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser shows the list of currently open opportunities: https://<instance>/apex/ActionParameter.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

Clicking on the Win button for the Grand Hotels Kitchen Generator opportunity updates the status to Closed Won and redraws the list of opportunities.

The page markup to send the parameter to the controller is as follows:

<apex:commandButton value="Win" action="{!winOpp}" status="status"
        rerender="opps_pb" 
        rendered="{!opp.StageName!='Closed Won'}">
   <apex:param name="oppIdToWin" value="{!opp.Id}" 
assignTo="{!oppIdToWin}" />
</apex:commandButton>

The <apex:param /> component defines the value of the parameter, in this case, the ID of the opportunity, and the controller property that the parameter will be assigned to – oppIdToWin.

Note

Note that there is a rerender attribute on the command button. If this attribute is omitted, making the button a simple postback request, the parameter will not be passed to the controller. This is a known issue with Visualforce as documented in the following knowledge article: http://help.salesforce.com/apex/HTViewSolution?id=000002664&language=en_US.

The property is declared in the controller in a normal way.

public Id oppIdToWin {get; set;}

Finally, the action method is invoked when the button is pressed.

public PageReference winOpp()
{
   Opportunity opp=new Opportunity(Id=oppIdToWin,
                                   StageName='Closed Won');
   update opp;
   return null;
}

The ID of the opportunity to update is assigned to the oppIdToWin controller property before the action method is invoked; thus, the action method can simply access the property to get the parameter value.

 

Reacting to URL parameters


URL parameters are used to pass information to Visualforce pages that the page or controller can then react to. For example, setting a record ID parameter into the URL for a page that uses a standard controller causes the controller to retrieve the record from the database and make it available to the page.

In this recipe we will create a Visualforce search page to retrieve all accounts where the name contains a string entered by the user. If the parameter name is present in the page URL, a search will be run against the supplied value prior to the page being rendered for the first time.

Getting ready

This recipe makes use of a custom controller, so this will need to be created before the Visualforce page.

How to do it…

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the SearchFromURLController.cls Apex class from the code download into the Apex Class area.

  4. Click on the Save button.

  5. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  6. Click on the New button.

  7. Enter SearchFromURL in the Label field.

  8. Accept the default SearchFromURL that is automatically generated for the Name field.

  9. Paste the contents of the SearchFromURL.page file from the code download into the Visualforce Markup area.

  10. Click on the Save button to save the page.

  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  12. Locate the entry for the SearchFromURL page and click on the Security link.

  13. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser retrieves all accounts where the name field contains the text ni: https://<instance>/apex/SearchFromURL?name=ni.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

The constructor of the custom controller attempts to extract a value for the parameter Name from the page URL, and if one has been supplied, executes the search.

public SearchFromURLController()
{
  searched=false;
  String nameStr=
    ApexPages.currentPage().getParameters().get('name');
  if (null!=nameStr)
  {
      name=nameStr;
      executeSearch();
  }
}

Note

Note that the constructor also sets the value retrieved from the URL into the Name property. This property is bound to the input field on the page, and causes the input field to be prepopulated with the value retrieved from the URL when the page is first rendered.

The action method that executes the search is as follows:

public PageReference executeSearch()
{
  searched=true;
  String searchStr='%' + name + '%';
  accounts=[select id, Name, Industry, Type from Account where name LIKE :searchStr];
    
  return null;
}

Tip

Note that searchStr is constructed by concatenating the search term with the % wildcard characters; this allows the user to enter a fragment of text rather than full words. Also, note that the concatenation takes place outside the SOQL query and the resulting variable is included as a bind expression in the query. If the concatenation takes place directly in the SOQL query, no matches will be found.

See also

  • The Passing parameters between Visualforce pages recipe in this chapter shows how URL parameters can be used to maintain the state across pages that do not share the same controller.

 

Passing parameters between Visualforce pages


If a user is redirected from one Visualforce page to another and they both share the same controller and extensions, the controller instance will be retained and re-used, allowing the second page to access any information captured by the first.

If the pages do not share the same controller and extensions, the controller instance will be discarded and the second page will have no access to any information captured by the first. If the state needs to be maintained across the pages in this case, it must be encapsulated in the parameters on the URL of the second page.

In this recipe, we will build on the example from the previous recipe to create a Visualforce search page to retrieve all accounts where the name contains a string entered by the user, and provide a way for the user to edit selected fields on all the accounts returned by the search. The record IDs of the accounts to edit will be passed as parameters on the URL to the edit page.

How to do it…

As the search page makes reference to the edit page, the edit page and associated custom controller must be created first.

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the EditFromSearchController.cls Apex class from the code download into the Apex Class area.

  4. Click on the Save button.

  5. Next, create the edit Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  6. Click on the New button.

  7. Enter EditFromSearch in the Label field.

  8. Accept the default EditFromSearch that is automatically generated for the Name field.

  9. Paste the contents of the EditFromSearch.page file from the code download into the Visualforce Markup area.

  10. Click on the Save button to save the page.

  11. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  12. Locate the entry for the EditFromSearch page and click on the Security link.

  13. On the resulting page, select which profiles should have access and click the Save button.

  14. Next, create the search page by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  15. Click on the New button.

  16. Paste the contents of the SearchAndEditController.cls Apex class from the code download into the Apex Class area.

  17. Click on the Save button.

  18. Next, create the Visualforce page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  19. Click on the New button.

  20. Enter SearchAndEdit in the Label field.

  21. Accept the default SearchAndEdit that is automatically generated for the Name field.

  22. Paste the contents of the SearchAndEdit.page page from the code download into the Visualforce Markup area.

  23. Click on the Save button to save the page.

  24. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  25. Locate the entry for the SearchAndEdit page and click on the Security link.

  26. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser retrieves all accounts where the name field contains the string United: https://<instance>/apex/SearchAndEdit?name=United.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

Notice that the page contains an Edit button, and clicking on this executes the following action method:

public PageReference edit()
{
  PageReference pr=Page.EditFromSearch;
  Integer idx=1;
  for (Account acc : accounts)
  {
    pr.getParameters().put('account' + idx, acc.id);
    idx++;
  }
    
  return pr;
}

This method initially creates a page reference for the edit page—EditFromSearch. It then iterates the accounts in the search results and adds an entry to the page reference parameters for the account ID. Each parameter has the name account, concatenated with the index of the result, starting from 1. This will result in a URL of the form https://<instance>/apex/EditFromSearch?account1=001i0000006OVLIAA4&account2=001i0000006OVLJAA4.

The EditFromSearch page then renders a form with an editable row per account.

The constructor of EditFromSearchController that manages the data for the page extracts the IDs from the URL and adds them to a list, starting with account1, until it hits a parameter index that is not present in the URL.

Integer idx=1;
String accStr;
do 
{
  accStr=ApexPages.currentPage().getParameters().
get('account' + idx);
  if (accStr!=null)
  {
    ids.add(accStr);
  }
  idx++;
}
while (null!=accStr);

The action method that saves the user's edits redirects them to the standard account tab once the save is complete.

return new PageReference('/001/o');

Note

Note that accessing the standard tab via this URL is not supported by Salesforce, and if the URL scheme or three character prefix for account (001) were to change, this redirection would stop working.

See also

  • The Reacting to URL parameters recipe in this chapter shows how a controller can process URL parameters prior to rendering a Visualforce page.

 

Opening a pop-up window


Pop-up browser windows have received mixed reviews in recent years. Originally created before tabbed browsers existed to display additional information without interfering with the page the user had navigated to, they were quickly hijacked and used to display advertisements and spam. Pop ups should be used sparingly in applications and wherever possible in response to an action by the user.

The target attribute can be specified as _blank on HTML hyperlink tags to open the link in a new window, but all modern browsers allow the user to specify that new windows should be opened as new tabs instead. Also, if the browser does open the URL in a new window, it will be of the same size as the existing window and block most of it. Opening a window in JavaScript allows for fine-grained control over many aspects of the pop-up window, for example, the size, and whether to display a toolbar.

In this recipe we will create a page that renders a list of accounts, displaying a very small subset of fields per row. A link will be provided on each row to allow the user to view full details of the account in a pop-up window.

Note

Note that there is no way to ensure that a browser will display a pop-up window. Pop-up blockers generally allow windows to be opened in response to an action by the user, such as clicking on a link, but it is possible for users to configure their browser to block all pop ups regardless of how they were triggered.

How to do it…

This recipe requires two Visualforce pages to be created: the main page containing the list of accounts and the pop-up window page. The pop-up page is referenced by the main page, so this will be created first.

  1. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  2. Click on the New button.

  3. Enter Popup in the Label field.

  4. Accept the default Popup that is automatically generated for the Name field.

  5. Paste the contents of the Popup.page file from the code download into the Visualforce Markup area.

  6. Click on the Save button to save the page.

  7. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  8. Locate the entry for the Setup page and click on the Security link.

  9. On the resulting page, select which profiles should have access and click on the Save button.

  10. Next, create the main account list page by navigating to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  11. Click on the New button.

  12. Enter PopupMain in the Label field.

  13. Accept the default PopupMain that is automatically generated for the Name field.

  14. Paste the contents of the PopupMain.page file from the code download into the Visualforce Markup area.

  15. Click on the Save button to save the page.

  16. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  17. Locate the entry for the PopupMain page and click on the Security link.

  18. On the resulting page, select which profiles should have access and click on the Save button.

How it works…

Opening the following URL in your browser displays a list of accounts: https://<instance>/apex/PopupMain.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

Note

Note that as this page uses a standard list controller, the list of accounts displayed will be that of the last list view that the user accessed.

The detail link markup is as follows:

<apex:outputLink title="View detail in a popup window" 
    onclick="return openPopup('{!acc.Id}');">
    Details
</apex:outputLink>

The onclick attribute defines the JavaScript function to be invoked when the link is clicked; note the {!acc.id} merge field, which passes the ID of the chosen account to the function.

The JavaScript function uses the window.open function to open the new window.

var newWin=window.open('{!$Page.Popup}?id=' + id, 'Popup',          'height=600,width=650,left=100,top=100,resizable=no,scrollbars=yes,toolbar=no,status=no');

The final parameter details the features required for the new window as a comma separated list of name=value pairs.

Clicking on the Details link displays the full account details in a pop-up window.

See also

  • The Adding a custom lookup to a form recipe in Chapter 3, Capturing Data Using Forms shows how information can be captured in a pop-up window and passed back to the main window to populate input fields.

 

Adding a launch page


When a Visualforce page is deployed to production, only users whose profiles have been given access via the security settings will be able to access the page. Any user with a profile that does not have access will receive an Insufficient Privileges error, which is not a good experience and can lead users to think that the page is crashing.

A better solution is to check whether the user has access to the page and if they do not, present a user-friendly message that explains the situation and directs them to where they can get more help.

In this recipe we will create a launch page accessible to all profiles that checks if the user has access to the protected page. If the user has access, they will be transferred to the protected page, while if they don't, they will receive an explanatory message.

How to do it…

This recipe requires a second user login. Ensure that this is not created with the System Administrator profile, as that profile has access to all Visualforce pages regardless of the security settings.

  1. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  2. Click on the New button.

  3. Enter Protected in the Label field.

  4. Accept the default Protected that is automatically generated for the Name field.

  5. Paste the contents of the Protected.page file from the code download into the Visualforce Markup area.

  6. Click on the Save button to save the page.

  7. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  8. Locate the entry for the Protected page and click on the Security link.

  9. On the resulting page, ensure that the profile of your second user does not have access to the Protected page.

  10. Log in using your second user credentials and attempt to access any account record. You will receive an error message as shown in the following screenshot:

  11. Next, create the launch page controller by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  12. Click on the New button.

  13. Paste the contents of the LaunchController.cls Apex class from the code download into the Apex Class area.

  14. Click on the Save button.

  15. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  16. Click on the New button.

  17. Enter Launch in the Label field.

  18. Accept the default Launch that is automatically generated for the Name field.

  19. Paste the contents of the Launch.page file from the code download into the Visualforce Markup area.

  20. Click on the Save button to save the page.

  21. Navigate to the Visualforce setup page by clicking on Your Name | Setup | Develop | Pages.

  22. Locate the entry for the Setup page and click on the Security link.

  23. On the resulting page, give access to all of the profiles and click on the Save button.

How it works…

Log in using your second user credentials and open the following URL in your browser: https://<instance>/apex/Launch.

Here, <instance> is the Salesforce instance specific to your organization, for example, na6.salesforce.com.

The resulting page displays a friendly error message detailing that your user does not have access to the page, and renders a clickable link to request access.

The Launch page declaration contains an action attribute.

<apex:page controller="LaunchController" action="{!allowAccess}">

This invokes the allowAccess action method in the controller before the page is rendered.

public PageReference allowAccess()
{
PageReference pr=Page.Protected;
   try
   {
       pr.getContent();
   	}
   catch (Exception e)
   {
       pr=null;
   }
        
        return pr;
    }

The allowAccess method attempts to retrieve the contents of the protected page programmatically. If the contents are retrieved successfully, it returns the page reference for the Protected page, which redirects the user to that page. If an exception occurs, the method returns null, which leaves the user on the Launch page and displays the friendly error message.

 

Testing a custom controller


Writing unit tests for Visualforce page controllers is often a source of confusion for developers new to the technology. A common mistake is to assume that the page must somehow be rendered and interacted with in the test context, whereas, in reality the page is very much a side issue. Instead, tests must instantiate the controller and set its internal state as though the user interaction had already taken place, and then execute one or more controller methods and confirm that the state has changed as expected.

In this recipe we will unit test SearchFromURLController from the Reacting to URL parameters recipe.

Getting ready

This recipe requires that you have already completed the Reacting to URL parameters recipe, as it relies on SearchFromURLController being present in your Salesforce instance.

How to do it…

  1. Create the unit test class by navigating to the Apex Classes setup page and by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the SearchFromURLControllerTest.cls Apex class from the code download into the Apex Class area.

  4. Click on the Save button.

  5. On the resulting page, click on the Run Tests button.

How it works…

The tests successfully execute as shown in the following screenshot:

Navigating back to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes shows that the tests have achieved 100 percent coverage of the controller.

Tip

Percentage coverage is important as at least 75 percent coverage across all code must be achieved before classes may be deployed to a production organization.

The test class contains two unit test methods. The first method tests that the search is correctly executed when the search term is passed on the page URL. As unit tests do not have access to organization data, the first task for the test is to set up three test accounts.

List<Account> accs=new List<Account>();
accs.add(new Account(Name='Unit Test'));
accs.add(new Account(Name='Unit Test 2'));
accs.add(new Account(Name='The Test Account'));
insert accs;

As the controller is reacting to parameters on the URL, the page reference must be set up and populated with the name parameter.

PageReference pr=Page.SearchFromURL;
pr.getParameters().put('name', 'Unit');
Test.setCurrentPage(pr);

Finally, the controller is instantiated, which causes the action method that executes the search to be invoked from the constructor. The test method then confirms that the search was executed and the actual number of matches equals the expected number.

SearchFromURLController controller=new 
         SearchFromURLController();
System.assertEquals(true, controller.searched);
System.assertEquals(2, controller.accounts.size());

The second unit test method tests that the search is correctly executed when the user enters a search term. In this case, there is no interaction with the information on the page URL, so the test simply instantiates the controller and confirms that no search has been executed by the constructor.

SearchFromURLController controller=new SearchFromURLController();
System.assertEquals(false, controller.searched);

The test then sets the search term, executes the search method, and confirms the results.

controller.name='Unit';
System.assertEquals(null, controller.executeSearch());
System.assertEquals(2, controller.accounts.size());

See also

  • The Testing a controller extension recipe in this chapter shows how to write unit tests for a controller that extends a standard or custom controller.

 

Testing a controller extension


Controller extensions provide additional functionality for standard or custom controllers. The contract for a controller extension is that it provides a constructor that takes a single argument of the standard or custom controller that it is extending. Testing a controller extension introduces an additional requirement that an instance of the standard or custom controller, with appropriate internal state, is constructed before the controller extension.

In this recipe we will create a controller extension to retrieve the contacts associated with an account managed by a standard controller and unit test the extension.

How to do it…

As the test class makes reference to the controller extension, this must be created first.

  1. Navigate to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  2. Click on the New button.

  3. Paste the contents of the AccountContactsExt.cls Apex class from the code download into the Apex Class area.

  4. Click on the Save button.

  5. Create the unit test class by navigating to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes.

  6. Click on the New button.

  7. Paste the contents of the AccountContactsExtTest.cls Apex class from the code download into the Apex Class area.

  8. Click on the Save button.

  9. On the resulting page, click on the Run Tests button.

How it works…

The tests successfully execute as shown in the following screenshot:

Navigating back to the Apex Classes setup page by clicking on Your Name | Setup | Develop | Apex Classes shows that the tests have achieved 100 percent coverage of the controller.

The test class contains one unit test method. As unit tests do not have access to the organization data, the first task for the test is to set up the account and contact information.

Account acc=new Account(Name='Unit Test');
insert acc;
    
List<Contact> contacts=new List<Contact>();
contacts.add(new Contact(FirstName='Unit', 
    LastName='Test', Email='[email protected]', 
    AccountId=acc.id));
contacts.add(new Contact(FirstName='Unit', 
    LastName='Test 2', Email='[email protected]',
    AccountId=acc.id));
insert contacts;

Next, the instance of the standard controller is instantiated.

ApexPages.StandardController std=
  new ApexPages.StandardController(acc);

Note that the standard controller requires the sObject record that it is managing as a parameter to the constructor. As this is the record that will be made available to the controller extension, it must have the fields populated that the extension relies upon. In this case, the only field used by the extension is the ID of the account, and this is automatically populated when the account is inserted.

Tip

In this recipe the records to be tested are created in the test classes. In the real world, this is likely to lead to a lot of repetition and a maintenance overhead. In that case, a utility class to handle the set up of test data would be a more robust solution.

Finally, the controller extension is instantiated, taking the standard controller as a constructor parameter, and the test verifies that the extension has successfully retrieved the associated contacts.

AccountContactsExt controller=new AccountContactsExt(std);
System.assertEquals(2, controller.contacts.size());

See also

  • The Testing a custom controller recipe in this chapter shows how to write unit tests for a custom controller that does not extend or rely upon another controller.

About the Author

  • Keir Bowden

    Keir Bowden is a 30-year veteran of the IT industry from the United Kingdom. After spending the early part of his career in the defence industry, he moved into investment banking systems, implementing systems for Banque Nationale de Paris, CitiGroup, and Deutsche Bank. In the late 1990s, Keir moved into Internet technologies, leading to a development of the order management and payment handling systems of one of the first European Internet shopping sites.

    Keir started working with Force.com in late 2008 and has been recognized multiple times by Salesforce as an MVP for his contribution and leadership in the community. In 2012, he became the first certified technical architect outside of Salesforce in EMEA, and he has served as a judge on several EMEA Technical Architect Certification Review Boards. Keir is also a prominent blogger on Apex, Visualforce and Lightning Components solutions; and a regular speaker at events such as Dreamforce, Cloud World Forum, and Salesforce World Tour.

    Keir is a chief technical officer of BrightGena—a Salesforce.com Platinum Cloud Alliance Partner in the United Kingdom, where he is responsible for the present and future technical strategies.

    Keir acted as a technical reviewer for the CRM Admin Cookbook before accepting the challenge of authoring this book, which also happens to be his first.

    Browse publications by this author