Using one page and controller for both a “Detail Page Button” and a “List Button”

See Correction section below the original post

Original Post

I have a Visualforce page that I want to use both for single objects (via a “Detail Page Button”) and for multiple objects (via a “List Button” with “Display Checkboxes” enabled). The page presents a table of the objects (with one row only for the single object case) and does its processing on each of the objects in the table.

This can be done with a single page and controller if the “URL” and “OnClick JavaScript” options are chosen for the “Content Source” of the custom buttons because then arbitrary parameters can be passed to an arbitrary page. But this post describes a way to get the “Visualforce Page” option for the “Content Source” to work instead. That means that the coupling between the buttons and page is more explicit, and more use is made of standard platform code and conventions.

The controller follows this pattern:

public with sharing class CustomObjectController {

  public CustomObject__c[] customObjects {get; private set;}

  public CustomObjectController(ApexPages.StandardSetController controller) {
    Id id = (Id) ApexPages.currentPage().getParameters().get('id');
    if (id != null) {
      controller.setSelected([
          select Id, Name, CustomField1__c, CustomField2__c
          from CustomObject__c
          where Id = :id
          ]);
    }
    this.customObjects = (CustomObject__c[]) controller.getSelected();
  }

  // Other controller logic
}

which is essentially a standard list controller with the bodge of special casing the presence of an “id” parameter. That bodge supports the single object case, at the cost of an explicit query being done.

The page also follows the standard list controller pattern by defining the recordsetvar attribute:

<apex:page
        standardcontroller="CustomObject__c"
        extensions="CustomObjectController"
        recordsetvar="customObjects"
        >
    <!--  Page content -->
</apex:page>

The good news is that this page can then be selected in the “Detail Page Button” case as well as the “List Button” case, allowing the single Visualforce page and Apex controller to be used in both cases.

Correction

I posted this too soon: I was mistaken that the list controller page could be assigned to a “Detail Page Button”. (A few too many similarly named pages in my development org…)

Here is a not very elegant work around. The list page shown above (lets call it “CustomObjectList”) remains unchanged. But a second page is needed (lets call it “CustomObject”) that does not have the recordsetvar attribute so that it can be assigned to the “Detail Page Button”. All that page does is forward to the “CustomObjectList” via this additional code (including a second constructor) added to the CustomObjectController:

public with sharing class CustomObjectController {

  // Other code as above

  private Id id;

  public CustomObjectController(ApexPages.StandardController controller) {
    id = controller.getRecord().Id;
  }
  
  public PageReference forwardToListController() {
    PageReference pr = Page.CustomObjectList;
    pr.getParameters().put('id', id);
    return pr;
  }
}
<apex:page
        standardController="CustomObject__c"
        extensions="CustomObjectController"
        action="{!forwardToListController}"
        />
Advertisements

5 thoughts on “Using one page and controller for both a “Detail Page Button” and a “List Button”

  1. Pingback: How To: Call Apex code from a Custom Button | Andy in the Cloud

  2. Have you tried having both constructors defined in the one controller class. The platform calls the approprite one depending on the VF page used then.

  3. I got an error while saving the code (Page.CustomObjectList). Can you post the code belongs to CustomObjectList . I want to know exactly what happens

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s