Create & Use Custom Controllers
Learning Objectives
After completing this unit, you’ll be able to:
- Explain what a custom controller is and describe its key attributes.
- Create a custom controller class.
- Use a custom controller on a Visualforce page.
Introduction to Custom Controllers
Add a custom controller to a Visualforce page by referencing the name of the controller class in the <apex:page>
controller
attribute.
When your page uses a custom controller, you can’t use a standard controller. Pages use a different attribute to set the custom controller.
- Open the Developer Console and click File | New | Visualforce Page to create a new Visualforce page. Enter
ContactsListWithController
for the page name.
- In the editor, replace any markup with the following.When you try to save this page, you’ll get an error, because
<apex:page controller="ContactsListWithController"> <apex:form> <apex:pageBlock title="Contacts List" id="contacts_list"> <!-- Contacts List goes here --> </apex:pageBlock> </apex:form> </apex:page>
ContactsListWithController
doesn’t exist yet. No worries, we’ll fix that next.
Create a Custom Controller Apex Class
A custom controller is just an Apex class, which you write yourself using the Developer Console.
There are a lot of system and utility classes to help you write custom controller logic, but the only requirement for a class to be used as a custom controller is that it exists.
- Open the Developer Console and click File | New | Apex Class to create a new Apex class. Enter
ContactsListWithController
for the class name.
In the editor, replace any code with the following.
public class ContactsListWithController { // Controller code goes here }
As with Visualforce pages, you need to save your changes to Apex when you change it. It’s not much, and it doesn’t do anything yet, but it does make the error go away on the Visualforce page.
- Switch back to the Visualforce page and save it again. The error message should go away, and the page is saved successfully.
- Click Preview to open a preview of your page that you can look at while you make changes. A new window should open, showing the standard Salesforce page header and sidebar elements, but no content yet.
At first glance, these two new items you’ve created don’t seem very interesting. But even though they are 90% placeholder code, the two items—Visualforce page and Apex controller—are linked to each other. As soon as you add some more code to the controller your page will be able to use it.
Beyond the Basics
You might have noticed that this custom controller class doesn’t inherit from another class, nor does it implement an interface promising to conform to the requirements of a Visualforce controller. Even complex controllers don’t do these things, because there isn’t any such class to inherit from or interface to implement. This leaves you free to create your own classes and interfaces as your experience with Apex increases.
Add a Method to Retrieve Records
Create a getter method that runs a SOQL query that returns records you want to display on your page.
The primary purpose of most controllers is to retrieve data for display, or handle updates to data. In this simple controller, all you need to do is run a basic SOQL query that finds contact records, and then make those records available to the Visualforce page.
- In the
ContactsListWithController
class, replace the// Controller code goes here
comment line with the following code.This code adds one private member variable, a string namedprivate String sortOrder = 'LastName'; public List<Contact> getContacts() { List<Contact> results = Database.query( 'SELECT Id, FirstName, LastName, Title, Email ' + 'FROM Contact ' + 'ORDER BY ' + sortOrder + ' ASC ' + 'LIMIT 10' ); return results; }
sortOrder
, and one public method,getContacts()
.sortOrder
is pretty easy to understand, it’s just the name of the field to sort the contacts by.getContacts()
is also fairly simple, but if you haven’t seen Apex before, it might be hard to parse at first. The effect of the method is to perform a SOQL query to get a list of contact records, and then return that list of contacts to the method caller. And who will the caller be? The Visualforce page, of course!
- In the
ContactsListWithController
page, replace the<!-- Contacts List goes here -->
comment line with the following markup.When you save this page you should see a familiar looking table of contact information.<!-- Contacts List --> <apex:pageBlockTable value="{! contacts }" var="ct"> <apex:column value="{! ct.FirstName }"/> <apex:column value="{! ct.LastName }"/> <apex:column value="{! ct.Title }"/> <apex:column value="{! ct.Email }"/> </apex:pageBlockTable>
The markup for the ContactsListWithController
page should look fairly familiar. Except for the controller
attribute of the <apex:page>
tag, it’s pretty much the same code you would use to create the page with the standard controller.
What’s different is what happens when the {! contacts }
expression is evaluated. On this page, Visualforce translates that expression into a call to your controller’s getContacts()
method. That method returns a list of contact records, which is exactly what the <apex:pageBlockTable>
is expecting.
The getContacts()
method is called a getter method, and it’s a general pattern, where {! someExpression }
in your Visualforce markup automatically connects to a method named getSomeExpression()
in your controller. This is the simplest way for your page to get access to the data it needs to display.
Add a New Action Method
Create action methods in your custom controller to respond to user input on the page.
Showing data is great, but responding to user actions is essential to any web app. With a custom controller, you can create as many custom actions as you want to support on a page, by writing action methods to respond to user activity.
- In the
ContactsListWithController
class, below thegetContacts()
method, add the following two methods.These two methods change the value of thepublic void sortByLastName() { this.sortOrder = 'LastName'; } public void sortByFirstName() { this.sortOrder = 'FirstName'; }
sortOrder
private variable.sortOrder
is used in the SOQL query that retrieves the contacts, and changingsortOrder
will change the order of the results.
- In the
ContactsListWithController
page, replace the two<apex:column>
tags forct.FirstName
andct.LastName
with the following markup.Although the visual appearance remains the same, if you click the First Name and Last Name column headers now, they will change the sort order for the contacts list. Nice!<apex:column value="{! ct.FirstName }"> <apex:facet name="header"> <apex:commandLink action="{! sortByFirstName }" reRender="contacts_list">First Name </apex:commandLink> </apex:facet> </apex:column> <apex:column value="{! ct.LastName }"> <apex:facet name="header"> <apex:commandLink action="{! sortByLastName }" reRender="contacts_list">Last Name </apex:commandLink> </apex:facet> </apex:column>
The new markup adds two nested components to each of the <apex:column>
components. <apex:column>
by itself has a plain text header, but we want to make the header clickable. <apex:facet>
lets us set the contents of the column header to whatever we want. And what we want is a link that calls the right action method. The link is created using the <apex:commandLink>
component, with the action
attribute set to an expression that references the action method in our controller. (Note that action methods, in contrast to getter methods, are named the same as the expression that references them.)
When the link is clicked, it fires the action method in the controller. The action method changes the sort order private variable, and then the table is rerendered. When the table is rerendered, {! contacts }
is reevaluated, which reruns the query with whatever sort order was just set. The final result is the table is resorted in the order requested by the user’s click.
Beyond the Basics
The header text for the first name and last name columns is hard-coded in this markup. But what if your users don’t all use English? The standard Salesforce user interface has translated versions of the field names for all standard objects, and you can provide your own translations for custom objects. How would you access these? Instead of the plain text, try this markup: <apex:outputText value="{! $ObjectType.Contact.Fields.FirstName.Label }"/>
. That’s the right way to reference a field’s label, even if your organization all uses the same language, because it will automatically update if the field name is ever changed.
Tell Me More...
Custom controllers and the Apex language let you do pretty much anything you can think of in your Visualforce pages.
Getter methods pull data out of your controller onto your page. There are corresponding setter methods that let you submit values from the page back up to your controller. Like getter methods, you prefix your setters with “set”, and other than that, they’re just methods that take an argument.
An alternative to getters and setters is to use Apex properties. Properties are kind of a combination of a variable with getter and setter methods, with a syntax that groups them together more clearly. A simple property that references a custom object might be declared like this.
public MyObject__c myVariable { get; set; }
Properties can be public or private, and can be read-only, or even write-only, by omitting the get or set. And you can create implementations for the get or set methods, when you want to perform additional logic besides simply saving and retrieving a value.
Properties are a general feature of Apex, not specific to Visualforce. Apex is a complete programming language, and in addition to being the natural partner for building complex Visualforce pages, it’s used in many other Lightning Platform development contexts. See the Apex topics elsewhere here, and the resources at the end of this page for many ways to learn to use Apex fully.
The lifecycle of a Visualforce request and response can seem complex initially. In particular, it’s important to understand that there’s no specific order in which getters or setters (or properties, if you use them) are called, so you must not introduce order-of-execution dependencies between them. There’s a lot more detail available to you in the relevant sections of the Visualforce Developer Guide, in particular the Custom Controllers and Controller Extensions chapter.
Resources
- Visualforce Developer Guide: Creating Your First Custom Controller
- Visualforce Developer Guide: Custom Controllers and Controller Extensions
- Apex Developer Guide
- Salesforce Developers Blog: Apex Template: Visualforce Controller
- Salesforce Developers Blog: A Real Controller for Visualforce Charting
- Visualforce Developer Guide: apex:outputLink Component
- Visualforce Developer Guide: apex:repeat Component