Custom Controllers

Custom controllers provide complete control over the behavior of a page with no default implementation. A custom controller is simply an Apex class designed to be bound to a Visualforce page. There is no new syntax to learn. At a high level, building a custom controller consists of defining the data to make available to the page and the actions that the page can invoke.

Exposing Data

The purpose of exposing data in a controller is to make it available to the page. Within a page, page components can use expressions to bind to it and render HTML or some other representation of the data. This binding is by reference, so data modified in the page can also be modified in the controller.

Simply making a variable public does not provide a Visualforce page access to it. The variable must have a getter method, a setter method, or both, depending on whether you intend to provide read-only or read and write access to the data.

For example, the page component inputText is an input and output component. It renders any existing or default value by invoking the getter and then invokes the setter to update the value after it is changed by the user and the page is submitted.

Expression language allows traversal of an object through dot notation, so providing separate getters and setters for every field in a database record, for example, is not necessary. Expose the object itself and use dot notation to access its fields. For example, the code in Listing 6.5 exposes a Project record for read-only access using the automatic properties feature of the Apex language. The read-only access is accomplished using the private access modifier keyword for the set accessor. Thanks to the Project getter, the page can contain expressions like {!project.Name} and even {!project.Account__r.BillingCity} because you’ve made the parent object’s field available through a SOQL statement in the constructor.

Listing 6.5 Custom Controller, Read-Only Access to Project Record


public class MyPageController6_5 {
  public Project__c project { get; private set; }
  public MyPageController() {
    project = [ SELECT Name, Account__r.BillingCity FROM Project__c
      WHERE Name = 'GenePoint' LIMIT 1 ];
  }
}



Caution

Placing business logic in the getter and setter methods is bad practice and, in many cases, prohibited at runtime. Make a habit of exposing data through Apex automatic properties rather than full getter or setter methods. Automatic properties do not allow a code body to be added.


Expressions are the closest you can get to business logic on the page without resorting to JavaScript. For example, you can combine expressions to form more complex expressions. The expression {!isVisible && isEditable} invokes both the getIsVisible and getIsEditable methods on the controller and evaluates to true if they are both true. Conditionals are also supported. For example, the condition expression {!IF(tabSelected, 'currentTab', 'secondaryPalette')} uses the value of the tabSelected method to determine whether to return one string (currentTab if true) versus another (secondaryPalette if false).

Writing Action Methods

Actions on a page are wired up to action methods in the controller, again by expression language. Action methods are public, nonstatic controller methods that return a PageReference object or null. If null, the current page is refreshed. If not, the PageReference is used to determine the location of the new page.

Actions have three purposes:

1. Preserve view state—The view state is maintained by Force.com within your page at runtime and posted back to its servers for the invocation of an action. It consists of the values of all of your controllers’ accessible, nontransient variables. It allows you to build stateful interactions consisting of multiple pages without writing boilerplate code to copy values around in hidden fields, in the URL, or by using stateful patterns in the controller such as session objects, which are not supported by Force.com. You can opt out of actions entirely, redirecting the user at a browser level using standard HTML anchors and forms. But by doing so, you’re circumventing some of the value provided by Visualforce and giving yourself extra work.

2. Invoke custom logic—Actions can perform some custom logic, such as using DML methods to upsert a record to the database. Other than the constructor, action methods are the only place you should write new business logic or call existing Apex code in a Visualforce controller.

3. Trigger page navigation—The PageReference object returned by an action determines the page to be refreshed in the browser. Construct a PageReference from a page name, such as new PageReference('MyPage'). The URL of the browser remains the same, but the body is refreshed with the contents of MyPage. This is not always desirable behavior, because a user can click the Reload button in the browser and potentially trigger the same action with the same input data. For example, this would result in duplicate records if the action code performs an insert DML operation. You can tell Force.com to redirect the user to the new page by calling the setRedirect method on the PageReference and passing true. A redirect updates the browser’s URL and resets the view state, giving the user a fresh start and preventing any problems with the browser’s Reload button.

Listing 6.6 is a sample controller to illustrate a common pattern in Visualforce: wrapping a database object with an Apex class. The wrapper object allows you to enhance a class for participation in user interface tasks, such as formatting data. In Listing 6.6, the wrapper exists to add a selected attribute. This attribute is bound to an inputCheckbox view component, shown in Listing 6.7, allowing the user to select multiple items. The action can then perform a mass update based on the selection. In the sample code, it simply outputs the unique identifier of each selected Project record to the debug log.

Listing 6.6 Controller with Wrapper Pattern


public class MyPageController6_6 {
  public List<ContactWrapper> contacts { get; set; }
  public MyPageController6_6() {
    contacts = new List<ContactWrapper>();
    List<Contact> records = [ SELECT Name FROM Contact ];
    for (Contact record : records) {
      contacts.add(new ContactWrapper(record));
    }
  }
  public PageReference doSomething() {
    for (ContactWrapper wrapper : contacts) {
      if (wrapper.selected) {
        System.debug(wrapper.data.Id);
      }
    }
    return null;
  }
  class ContactWrapper {
    public Contact data { get; private set; }
    public Boolean selected { get; set; }
    public ContactWrapper(Contact data) {
      this.data = data;
      this.selected = false;
    }
  }
}


Listing 6.7 Page with Wrapper Pattern


<apex:page controller="MyPageController6_6">
<apex:form>
  <apex:pageBlock title="Sample Code">
    <apex:pageBlockButtons >
      <apex:commandButton action="{!doSomething}"
        value="Do Something" />
    </apex:pageBlockButtons>
    <apex:pageBlockTable
      value="{!contacts}" var="contact">
      <apex:column headerValue="Selected">
        <apex:inputCheckbox value="{!contact.selected}" />
      </apex:column>
      <apex:column headerValue="Contact Name">
        {!contact.data.Name}
      </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlock>
</apex:form>
</apex:page>



Tip

To clearly differentiate your controller code from triggers and other Apex code, adopt a naming convention and stick to it. A good one is to suffix your class name with the word Controller.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.161.42