Navigation: Developer Force | Visualforce | Using the Standard Controller


Building Visualforce Pages Using Standard Controllers

by Don Robins

Vis cover thumb.jpg

While most developers are familiar with the Standard Controller, even experienced developers may not be aware of how powerful this built-in controller functionality is. While it is generally understood that a standard controller provides management of views, data, and actions in Salesforce, there is often confusion regarding exactly what a standard controller is.

It might appear that a standard controller is a component or class, pre-existing for standard sObjects and auto-generated for newly created custom sObjects at design time. Some might speculate from some of the formal documentation (ie. “Every standard controller includes a getter method that returns the record specified by the id…”) that they exist as classes in Apex or Java not visible to developers.

It is probably more accurate to represent a standard controller, not as a component or class, but rather as a consistent set of user interface and data operation instructions. It is automatically provided by the Force.com engine, and available at design and runtime for most standard and all custom sObjects.

It is tightly integrated with sObject metadata, configurable for each sObject, and it drives the runtime page materialization, record management and action processing of most of the built-in user interface. This includes dialogs, search layouts, record detail page layouts, as well as record list views and the associated actions and behavior.

Focusing on how a standard controller is implemented and delivered by the Force.com platform is far less important than focusing on what it provides. What is most important to understand is how central it is to managing the user interface, navigation and data operations on sObjects, regardless of whether or not a developer chooses to implement custom Visualforce pages, with or without Apex logic.

What Does a Standard Controller Do?

The interaction between a user and their business data can be simple or complex, but nonetheless requires a detailed set of instructions and rules to be managed. It is the controller that provides such management, while preserving a clean separation between the view layer and the data model.

In the MVC pattern, Views know how to present their data and accept input from the user, but know nothing about how to actually fetch that data or process it. Data Models know how to perform various operations such as Save, Delete or Merge, but need to be told when to operate, and need to be provided with the data to operate on.

It is the Controller’s job to marshal both data and action selection, as initiated by the user from within the View, to the Model. Controllers are also responsible for responding accordingly with navigation redirection based on the results of any particular action. In the Salesforce MVC paradigm, it is the standard controller that facilitates the ability of users to access and interact with the structured business data contained in records and displayed in the materialized user interface.

A standard controller’s tasks are as follows:

  • Controlling Data: Standard controllers fetch data and provide it to the page, list, dialog or form, all referred to here as views. While it is the view’s task to manage the presentation of its data, the controller gathers the data from the view as entered or changed by a user, and passes it to the data model for processing.
  • Controlling Actions: Standard controllers respond to user or programmatic commands initiated from a view. Such commands, referred to as Actions, might be associated with processing the data gathered from the view, or simply to respond to a navigation link.
  • Controlling Navigation: Standard controllers navigate the user to any specific view associated with an action. They also handle redirection to subsequent views, based on the specific outcome of various actions and data operations.

Developers might assume that they must resort to the implementation of custom Apex logic to provide complex functionality that their applications require, yet might be unaware that such functionality might already be available to them in Visualforce via standard controller mechanisms.

It is a best practice to make sure you understand what is available to leverage in the standard controller layer before you begin to design and build your own custom pages and controllers to avoid ‘reinventing the wheel.’

Let’s break down the standard controller into its core parts, focusing on both the common and less obvious aspects to clarify what is automatically available in the Force.com standard controller instruction set.

CONTROLLING VIEWS

Materializing a User Interface

The metadata-driven user interface is one of the most powerful aspects of the Force.com platform, making development of business applications both rapid and cost effective.

Using no code, complex relational database applications can be configured and deployed in short order because the standard user interface for each sObject, including the Home Page, List Views, Search Dialogs, Detail and Edit pages, are all materialized by the Force.com engine at runtime, and managed by standard controller functionality.

The controller mechanism utilizes each sObject’s default or customized metadata, field configuration, and other various settings available on the detail setup page.

There is a minimum metadata configuration provided by default for each standard sObject delivered with a new org, and for each custom sObject created that includes the following:

  • Inclusion of a hyperlinked standard Name field in all list views and dialogs. These views can be further configured to display additional fields.
  • A default page layout including all standard fields, (other than the record ID,) pre-existing for standard sObjects and initially generated and configured for each new custom sObject.
  • Custom fields added to any sObject are added to page layouts by default at design time, although the user can choose to exclude them.
  • During the creation of relationships on child sObjects, users can choose to include related lists on page layouts of the related parent sObject.
  • During the creation of custom fields, profile-based, field-level security is defaulted to allow read/write access to all new fields to all users of all profiles, but the user can customized access as needed.

All of this related metadata is used by the standard controller engine to auto-render a basic user interface with the appropriate data display or input controls, whether ‘out of the box’ or customized by a developer.

Standard User Interface Flow

The typical standard User Experience (UX) is as follows for any standard or custom data management in Salesforce:

  • A user logs into their Salesforce org and is presented with those applications to which they have rights. Once an application has been selected, the associated tabs are displayed. Developers should realize that Apps and Tabs are in themselves a configurable view.
  • Selecting any tab (our focus will be on sObject Tabs rather than Visualforce or Web tabs), directs the user to a set of views managed by the standard controller, (for the selected sObject,) that follows a consistent navigation path.
  • The initial tab displayed is the Home Tab for that sObject, displaying a dropbox selector of available list views, and a list of any recently viewed records. Various standard sObject Home Tabs also display additional information, such as reports or tools, etc.
  • A user can select one of the available list views from the dropbox, the All view is present by default. Or they can select to navigate to one of the listed ‘Recent’ links which will direct them to the detail view of the selected record.
  • Selection of a list view displays all records matching the filter and column configuration, the default **All* view displays all records with just the hyperlinked Name field. List views may be added or customized, allowing users to select column display configuration and list filtering. These mechanisms are managed by the standard controller instruction set. You might also note that this same set of list views are available to leverage with programmatic access within a Visualforce page.
  • Selection of any record will navigate to its detail view, which is rendered based on the associated sObject page layout metadata. The user’s access to buttons and links will be mitigated by the standard controller based on the user’s permissions, or as configured in the page layout. If there are page layout and record type assignments configured, the appropriate layout will be used based on the user’s profile assignment.
  • The various buttons invoke the associated actions, associated navigation and processing, again all managed by the standard controller instruction set.

This user experience flow might seem obvious for any user who is familiar to Salesforce. However, our purpose is to make it clear that the control of the navigation path, the management of the data components displayed on each view, the rendered controls, links and their associated actions, the configuration of the display and filtering criteria of the list views; all are delivered by the standard controller instruction set working behind the scenes as driven by the Force.com engine.

This configurable behavior, whether default or customized, is persisted in the metadata of 
the associated sObject, and might also be affected by other means, such as user profile 
permission configuration.

Each of the primary data views associated with a set of standard actions on any sObject can be overridden with a custom Visualforce page. Page layouts, which are also configurable, can contain nested Visualforce pages as well.

The best part is that the greater majority of the controller instruction set capabilities are available to developers to access programmatically from their Visualforce pages, with or without underlying Apex controller or extension logic.

This foundation-level understanding of what the Force.com engine does is beneficial to 
guiding your development effort when building custom functionality, so let’s take a closer look.

CONTROLLING DATA

Referencing a Single Record

No page, standard or custom, would be of much use to a user without some data to operate on. One of the key tasks of the standard controller is to provide that data, and to facilitate binding a view’s controls to the record’s fields, for either display or input.

Data binding to Visualforce components is relatively straight forward, but there is an aspect of managing field data that is a bit more obscure.

As most developers know, we can associate a standard controller with a Visualforce page by use of the standardController attribute on the component. We simply identify the standard or custom sObject for the controller as follows:

<apex:page standardController=”Account” >

Once bound, the page associates within the context of the specified sObject. The standard controller will provide the data from an associated record and allow the record’s fields to be bound to the page’s various components using merge expression syntax. This is the same merge syntax used in formula expressions, email templates, and anywhere that field values need to be merged for expression evaluation:

<apex:inputField value={“!Account.name”} />

Values of any specified fields associated with the controller’s sObject are accessed using standard dot notation. The name of the sObject is used to represent the record instance. Fields on related parent sObjects, (whether a lookup or master-detail relationship,) can also be referenced and bound:

<apex:inputField value={“!Account.Owner.Firstname”} />

Lists of records from child sObjects can be referenced and bound to components that render collections. Note that the value of the list attribute is the literal name of the field representing the child relationship:

<apex:relatedList list=”Contacts” />

The standard controller requires record context that can be provided by including a URL parameter named ‘id’ and assigned with a valid 15- or 18-digit record ID. The record specified by the ID must match the sObject type associated with the StandardController on the page, or an error will be thrown when the page attempts to render:

https://naX.salesforce.com/apex/CustomAccountPage?id=001A0000005HjZL

This is slightly different than the URL pattern to access a standard detail page for any record, which simply requires that the record id follow the Salesforce server instance name:

https://naX.salesforce.com/001A0000005HjZL

This standard URL pattern is referred to as a ‘Frontdoor URL’, and is available to invoke a view, edit and insert of a record, as well as some other actions. We’ll take a closer look at this syntax a bit later, but for now just note that both of the above approaches require the record id to be present in the URL.

This allows the standard controller to fetch the data for the referenced record, and makes the values of all referenced fields available through the sObject reference for binding.

Loading Field Values

The key in the sentence above is referenced fields. What might not be obvious is that the standard controller will automatically populate the underlying sObject instance with only those fields explicitly bound to components included in the page.

In other words, while all fields in the schema of the referenced sObject are available for binding to Visualforce page components, only those fields explicitly bound to components on the Visualforce page will have their values fetched by the underlying query managed by the standard controller; excluded field values will not be available for reference.

This is not unlike how a developer must explicitly include fields in a SELECT clause of a SOQL query in Apex on any target sObject in order to obtain their values and be able to programmatically manage them.

Just as in the Apex scenario when runtime code attempts to access a field not explicitly specified in a SOQL query, if code in a Visualforce page attempts to reference a field that has not been explicitly bound on the page, an error will be thrown at runtime and presented to the user. This can also occur when the StandardController instance is passed into an Apex custom controller extension as a parameter on the class constructor. If the record is retrieved by use of the getRecord() method on the StandardController instance, and some Apex code attempts to reference a field not bound on the page, an exception will be thrown.

An error will also occur during page rendering if such an excluded field is referenced elsewhere in the Visualforce page. This can be in a formula function bound to a component, perhaps built into a link component, or referenced somewhere in a block of Javascript. Regardless, in any such scenario, if the field value is not available, an error will occur.

One simple solution to extend the set of fetched field values is to add a hidden, non-visual or 
un-rendered Visualforce component to the page and bind the necessary field to the component’s value attribute. This will cause the field’s value to be included when populating the sObject instance.

For example, if you want the lookup ID value of a Contact’s parent Account available for a navigation link, including only a reference to the field value when constructing the link, or including it as a parameter in a URLFOR() function, will not cause the field’s value to be fetched by the standard controller from the database.

You will have to explicitly bind the field as a value attribute to some other Visualforce component, and if you don’t want the value displayed, you will need to set the rendered attribute to false:

 <apex:outputText value=”{!contact.accountId}” rendered=”false”/>  

To make your code a bit less confusing to other developers who might wonder why the component exists if never being rendered, binding the field to a variable component will also work:

 <apex:variable value=”{!contact.accountId}” var=”accountId” />  

Once bound it will be available for reference elsewhere on the page.

Loading Field Values in Apex

We won’t go into too much detail regarding custom controllers and Apex, but it’s worthwhile to simply note that this same issue might occur when using an Apex controller extension class with a referenced StandardController when your code needs to access fields on the sObject that have not been bound in the Visualforce page.

You can programmatically add additional fields in Apex using the addFields() and reset() instance methods on the referenced StandardController instance passed into the extension class constructor. The addFields() method takes a single argument of a String[] collection containing a list of those field you wish to populate.

There are some important considerations however when using these methods.

  • The addFields() method must be called before referencing the sObject with the getRecord() method.
  • Any pending changes to the record will be lost when the addFields() method is called.

The following example shows where the method is called in the constructor just before getting the record:

 public class DemoControllerExt {  
      public DemoControllerExt(ApexPages.StandardController controller){
           controller.addFields(new List<String>{‘accountId’});                 
           Contact contact=(Contact) controller.getRecord();                
            ...         
{
         ... }  

You can add more fields to the list later in code and call the reset() method to refetch the record which will include all of the desired field values specified.

A word of caution when unit testing your controller extension classes. Documentation on these methods tells us that they are only for use with “controllers used by dynamic Visualforce bindings,” suggesting that reset() and addFields() only work when the standard controller on a Visualforce page is responsible for loading the data. The implication is that if your Apex unit test code is responsible for setting up an sObject, explicitly instantiating a standard controller instance with that sObject, and then passing that standardController instance into a controller extension class for testing purposes, these methods won’t function as expected.

You will need to have your test sObject completely loaded with all desired field values before instantiating a StandardController instance to pass to the constructor when instantiating the Apex controller extension class for your tests. In addition, you will likely want to conditionally execute your addFields() code only if not in a testing context:

 if( !Test.isRunningTest() ){
         controller.addFields(new List<String>{‘accountId’});         Contact contact=(Contact) controller.getRecord();
  }  

Referencing a List of Records

The standard controller instruction set also manages lists of records, such as in standard list view pages where users can configure both the fields displayed in columns, as well as filters on the records displayed.

The StandardController as bound to a Visualforce page is also capable of fetching a list of records and managing paging through the list. Its behavior as a set controller is activated by adding an additional parameter named recordSetVar on the apex:page component.

<apex:page standardController=”Account” recordSetVar=”accounts” >  

Leveraging this mechanism allows your page to operate on a collection of the specified sObject bound to the controller.

The recordsSetVar specified becomes a reference to a List of the sObjects, and the controller will now have the following additional actions available to be directly bound to command controls, (in addition to the primary set of actions available on a bound StandardController managing only one sObject):

  • first displays the first page of records in the set.
  • last displays the last page of records in the set.
  • next displays the next page of records in the set.
  • previous displays the previous page of records in the set.

You also have access to two new attributes, filterId and listViewOptions for managing list view selection and applying filters.

There are quite a few instance methods available on the Apex system-delivered class ApexPages.StandardSetController, and a variety of practical development patterns to use when managing lists of records in Visualforce.

You’ll want to dig into the standard Visualforce documentation for details on the instance class methods, and we will revisit the standard set controller for some of these concepts in Chapter 5.

CONTROLLING ACTIONS AND NAVIGATION

Actions as Navigation

A controller’s primary functions include responding to and processing user actions as initiated from any associated view. The Salesforce standard controller is no exception, and in the Force.com platform, actions are primarily navigation based.

Actions are processed by the standard controller instruction set on the server, they may or may not result in the processing of data, and are responsible for determining subsequent navigation to the next appropriate page, often depending on the result of the action.

There are two ways to bind Visualforce components to actions made available on sObjects through the standard controller instruction set.

  1. Stateful Actions: direct binding to a standard controller instance referenced by the page.
  2. Stateless Actions: indirect binding to the standard controller instruction set of the Force.com engine.

Stateful Actions

Stateful actions are those available to be bound to Visualforce components directly from the standard controller as referenced on the page by its standardController attribute, and are dependent upon a form submission. Actions can also be submitted with AJAX calls from JavaScript, and in both cases subsequent navigation redirection will be dependent upon the action invoked and its outcome.

Such actions are most commonly bound to either an apex:commandLink or apex:commandButton component, and invoked by a user clicking the control. Because these command components are always associated with a form submission, they must always be nested in an apex:form component or the Visualforce page will not compile at design time.

These same controls can also call AJAX processes by setting their rerender attribute to reference the ID of some other component on the page. In this scenario, they will execute an asyncronous call behind the scenes via JavaScript, and are typically used to render a partial page refresh.

While AJAX is discussed in detail elsewhere in this book, suffice to say that these processes all typically result in some form of HTTP request back to the Force.com server and are managed by the standard controller. These requests may also contain additional URL parameters, added by use of the apex:param component.

Developers can also construct their own URLs to execute actions or expose links to any desired web page. We’ll discuss the use of the URLFOR() function that allows this programmatic navigation when we discuss stateless actions.

Stateful Action Mechanisms

The Visualforce stateful action components are most typically bound to a common set of standard controller actions available for all sObjects associated with any standard controller as referenced on the page.

The most commonly used action components include:

  • apex:commandButton which renders a button that calls an action.
  • apex:commandLink which renders a link that calls an action.
  • apex:page can call an action upon load with its action attribute.

Additional components are available specifically designed for AJAX processing:

  • apex:actionPoller which calls an action on a timer.
  • apex:actionSupport which binds to a JavaScript ‘on’ event on a referenced component to call an action.
  • apex:actionFunction that generates code for a JavaScript function to call an action.

The following are the common actions which can be invoked in the context of the sObject associated with the referenced standard controller:

  • List: navigates the user to the default list view.
  • View: navigates to the default detail page.
  • Cancel: aborts an edit operation, and returns the user to the page where the user originally invoked an edit or insert.
  • Save: inserts a new record or updates an existing record in context, and then returns the user to the default detail page for the saved record.
  • QuickSave: inserts a new record or updates an existing record in context, but unlike the save it does not redirect the user to another page but leaves the user on the page where the action was initiated from.
  • Edit: navigates to the edit page for the record in context, and then whether saved or cancelled, returns the user to the page where the action was originally invoked.
  • Delete: deletes the record in context, and then navigates the user to the Home Tab of the associated sObject.

Here is an example of the direct binding syntax for each with an apex:commandButton component:

 <apex:commandButton action=”{!list}” value=”List” />  
 <apex:commandButton action=”{!view}” value=”View” />  
 <apex:commandButton action=”{!cancel}” value=”Cancel” />  
 <apex:commandButton action=”{!save}” value=”Save” />   
 <apex:commandButton action=”{!quickSave}” value=”Quick Save” />             
 <apex:commandButton action=”{!edit}” value=”Edit” />     
 <apex:commandButton action=”{!delete}” value=”Delete” />     

It is important to note that the subsequent navigation of the user following the action invocation is dependent upon the outcome of the action, as well as the original location of the user when the action was initially invoked, and there can be many permutations.

You may also note the conspicuous absence of a few important and very common sObject standard actions such as New, Share, and Clone. There are many more specific actions that may also be available on different standard sObjects.

If you take a look at the detail setup views of any standard sObjects, in the related list ‘Buttons, Links and Actions’ you will see that each may have its own additional set of specific actions, like Close on Cases, Accept on Leads, or Advanced Setup on Campaigns.

Figure 2-1: Contact Actions


Figure 2-2: Account Actions

Demo Custom sObject Actions

These actions, and dozens more, are certainly managed by the standard controller in the materialized user interface. So how can they be called programmatically if they can not be directly bound to stateful Visualforce action components?

Figure 2-3: Case Actions

Summary

It’s amazing how quickly you can create custom forms and UIs that access data securely using Visualforce and standard controllers. While it's easy to overlook standard controllers as a means for creating custom pages, you will often find that functionality is already available through standard controller mechanisms, and there's little need to resort to write custom Apex Code to support complex functionality.

Part 2 of this series looks at how a standard controller can be leveraged when extended by a custom apex controller extension. Part Two also examines an alternative mechanism available to developers for binding standard and custom sObject actions to both stateful and stateless Visualforce components, (those requiring a form submission or not,) as well as invoking them from custom buttons and links on standard page layouts. In the process, we'll also dive into the URLFOR() function, and show how to add URL parameters on Actions using URLFOR().


This article was excerpted from Visualforce in Practice, published by salesforce.com, November 2013 and released at Dreamforce '13.