Passing standard controller SObject to a component: problem with custom fields

You only get "one bite at the cherry" with the Standard Controller. But If you can afford to put the markup in the entry point page, this may be worth noting:

  • apex:include targets cannot traverse standard controllers
  • but apex:composition defines can traverse included pages

Fields can only be queried automatically via a StandardController on an apex:page. Even though apex:include is unavilable in apex:component, you can cheat by moving your component body to a page, then doing a poor-man's include (parameterized PageReference.getContent) from the component controller.

Then, communicate the Campaign Id into your component so it can be requeried. Here's an example:

  • the Campaign Name is queried from the Page
  • the Campaign Status is queried from the Component

poor man's include

CustomCampaign.page

<apex:page standardController="Campaign">
  <apex:sectionHeader title="{!Campaign.Name}" />
  <c:importCampaign campaignId="{!Id}" />
</apex:page>

ImportCampaign.component

<apex:component controller="ImportCampaignController">
  <apex:attribute name="campaignId" type="Id" description="Id" assignTo="{!IdParam}" />
  <apex:outputText escape="false" value="{!Include}" />
</apex:component>

ImportCampaignController.cls

public class ImportCampaignController {

  public Id IdParam {get; set;}

  public String getInclude() {
    System.PageReference pageReference = Page.ImportCampaignBody;
    pageReference.getParameters().put('id', this.IdParam);
    return pageReference.getContent().toString();
  }

}

ImportCampaignBody.page

<apex:page standardController="Campaign">
  <apex:sectionHeader title="Status: {!Campaign.Status}" />
</apex:page>

(special thanks to Andrew Fawcett for sanity checking and analyzing this and multiple other approaches)