function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
snh_nitsnh_nit 

Visualforce email template issue

Hi all,

 

I have a Visualforce email template which includes a component which has it's own custom controller. I use this setup in order to be able to retrieve related objects which I want to display in the email going out to a contact.

 

However, for some reason, nothing gets displayed in my email templates and I haven't found a way of debugging it in order to be able to track when/where it goes wrong. However, I'm fairly certain that it is the opportunity ID that does not get passed from the template/component to the controller.

 

I've searched for an answer but haven't been able to find one. I've seen similar posts (e.g.. http://forums.sforce.com/t5/Apex-Code-Development/Custom-Controller-in-Email-Template-not-passing-values-to-Class/m-p/134744) but for some reason I still haven't been able to make it work in my own org.

 

Here is my component:

 

<apex:component id="cmpOrderForm" controller="OrderFormDomainOppComponentController" access="global">
	<apex:attribute name="paramOppId" description="Passes the ID of the opportunity to the custom controller" type="Id" assignTo="{!oppId}"/>
	<apex:outputText value="{!oppId}"/>
	<html>
		<body>
			<table>
				<apex:repeat value="{!links}" var="lnk">
					<tr>
						<td>Domain Name</td>
						<td>{!lnk.Domain__r.Name}</td>
					</tr>
				</apex:repeat>
			</table>
		</body>
	</html>
</apex:component>

 Here is my template:

<messaging:emailTemplate recipientType="Contact" relatedToType="Opportunity" subject="Order Form" replyTo="soren.nodskov@capgemini.com">
    <messaging:htmlEmailBody >
    	<c:OrderFormDomainOppComponent paramOppId="{!relatedTo.Id}"/>
    </messaging:htmlEmailBody>
</messaging:emailTemplate>

 Here is my controller:

public without sharing class OrderFormDomainOppComponentController {
	private final List<DomainOppLink__c> links;

	public Id oppId {get; set;}

	public OrderFormDomainOppComponentController() {
		// oppId = '006W0000002VDzZ';
		links = [SELECT Domain__r.Name FROM DomainOppLink__c WHERE Opportunity__c = :oppId];
	}

	public List<DomainOppLink__c> getLinks() {
		return links;
	}
}

 In the template I output the Opportunity ID just for debugging purposes and that works fine. It shows the ID correctly when testing the template from within the SF GUI (Setup --> Communication Templates --> Email Templates).

 

However, the DomainOppLink objects retrieved in the controller is not shown. If I hard code the opportunity ID in my controller (commented out in the code above), it all works fine. I.e.. I get an email with all the DomainOppLink objects.

 

So, the big WHY is: WHY doesn't it work when I am NOT hard coding the opportunity ID but using the ID passed on from my component/template?!

 

I feel like I'm SO close, and that I just cannot seen the forrest for all the trees.

 

All help is greatly appreciated.

 

Cheers.

 

/Søren Nødskov Hansen

Best Answer chosen by Admin (Salesforce Developers) 
t_Christ_Chris

Try this as your controller... it fixed the issue for me...

 

public without sharing class OrderFormDomainOppComponentController {

	public Id oppId {get; set;}

	public OrderFormDomainOppComponentController() {
		// oppId = '006W0000002VDzZ';
	}

	public List<DomainOppLink__c> getLinks() {
		return [SELECT Domain__r.Name FROM DomainOppLink__c WHERE Opportunity__c = :oppId];
	}
}

 

All Answers

t_Christ_Chris

Hi,

 

I am having the EXACT same problem, have you manged to find a solution to this?  I'll post back if I find anything.

 

Cheers

 

Chris

t_Christ_Chris

I think the problem may be in having the bulk of the logic inthe constructor.  I just created a simple getMethod()  to create a test variable and it seemed to work ok

 

Going to see if I can refactor my code to work this way.

t_Christ_Chris

Try this as your controller... it fixed the issue for me...

 

public without sharing class OrderFormDomainOppComponentController {

	public Id oppId {get; set;}

	public OrderFormDomainOppComponentController() {
		// oppId = '006W0000002VDzZ';
	}

	public List<DomainOppLink__c> getLinks() {
		return [SELECT Domain__r.Name FROM DomainOppLink__c WHERE Opportunity__c = :oppId];
	}
}

 

This was selected as the best answer
snh_nitsnh_nit
Thanks, Chris. I haven't tested it yet, but I'm certain it will work. It makes perfect sense, once you sit down and think about it.. the issue is, of course, that the constructor is the very first thing that is initialized and the getters and setters are then initialized afterwards. So, the SOQL in the constructor is called with 'null' and then the getter and setter its called. That's why it prints the opportunity ID correctly when testing, and why it works with a heard coded value Thanks for making me think :) /Søren Nødskov Hansen
t_Christ_Chris

Ah, yeah!  I hadn't even thought that the setter needed to run first on the attribute!  it's been a long day!

snh_nitsnh_nit
Changed, tested and it works according to spec. Now I can enjoy my 2 days off :) /Søren Nødskov Hansen