[SalesForce] How to pass paramaters from an email template into a custom component

setup:

Opportunities are related in a MDR to children__c object. When my opp reaches a stage, an email alert (via workflow) gets sent out with the opp info. I want to include a list of urls for the children record related to that master opp. I did some reading- and it looks like custom components do the trick.

questions:

  1. is this the right approach?
  2. how do i pass params to the custom compoenent from the email template?

EDIT- Code:

Apex Class

    public with sharing class BenefitChecklistEmailTemplateHelper {
        public list <Benefit_Checklist__c> checklists;
        public String oppId {get; set;}

        public BenefitChecklistEmailTemplateHelper(){
            system.debug('oppid :' +oppId);
            this.checklists = [select id, name from Benefit_Checklist__c where Opportunity__c = :oppId];

        }   
}

Custom component

    <apex:component controller="BenefitChecklistEmailTemplateHelper" access="global">
    <apex:attribute id="oppId" assignTo="{!oppId}" name="opportunityIDFromEmail" type="ID" description="The Opporunity's SF ID"/>    
       <table border="0" >
             <tr>
                 <apex:repeat var="c" value="{!Checklists}">
                    <tr>
                        <td><a href="https://na1.salesforce.com/{!c.id}">View</a> </td>
                        <td class="sub_section_label">Checklist Name</td><td class="sub_section_data">: {!c.id}</td>
                    </tr>
                </apex:repeat>   
            </tr>              
        </table>
    </apex:component>

Email Template

    <c.BenefitChecklistEmailTemplateHelper opportunityIDFromEmail="{!relatedTo}"/>

Best Answer

You have two options here, one with and one without a custom component.

Without Custom Component. If your using a Visualforce Email Template you can use the apex:repeat take to reference the child records of your Opportunity. From the link the following sample shows how to list related Cases to an Account.

<table border="0" >
    <tr >
        <th>Action</th><th>Case Number</th><th>Subject</th><th>Creator Email</th><th>Status</th>
    </tr>
    <apex:repeat var="cx" value="{!relatedTo.Cases}">
        <tr>
            <td><a href="https://na1.salesforce.com/{!cx.id}">View</a> | 
            <a href="https://na1.salesforce.com/{!cx.id}/e">Edit</a></td>
            <td>{!cx.CaseNumber}</td>
            <td>{!cx.Subject}</td>
            <td>{!cx.Contact.email}</td>
            <td>{!cx.Status}</td>
        </tr>
    </apex:repeat>                
</table>

With Custom Component. You can create a custom componnet that takes as an attribute an instance of your Opportunity (or its Id) who's controller then performs a SOQL query (or uses a relationship dereference, see note) for the child records. The component itself uses a apex:repeat tag. The reason you might want to do this, is to sort the child records or do additional processing on them to expose further information (you could not generate via formula fields for example).

<c:showMyChildren opportunity="{!relatedTo}"/>

NOTE: You can avoid the custom component doing a requery, if you include in your email template a render="false" apex:repeat for the information you want, its never displayed, but gives the Visualforce runtime enough of a hint to query the information, allowing the custom component to access this information via the passed in Opportunity.

Update following Revised Answer

I spotted a couple of things with your implementation of option 2 above.

  • Your component attribute takes an Id so you need to pass the Opportunity Id not the whole Opportunity record (which is what 'relatedTo' points to). Try changing it to opportunityIDFromEmail="{!relatedTo.Id}"/>
  • The 'oppId' property of your controller will not have been set by the time the constructor of your component controller is called. Its an often a pitfall when writing component controllers. As properties are set in an indeterminate order, its best to differ process until one of your output accessor methods is called, in this case your getChecklists() method, move your constructor code into this method.