+ Start a Discussion
Tolga SunarTolga Sunar 

Visualforce - Standardcontroller components are not rendering when called from JS

I am trying to preview the email template inside a Visualforce page, and for this purpose, I query for the EmailTemplate record's body inside JavaScript, and then I let the standardcontroller do rest of the job by merging the referenced fields in email template - at least that's my intention.

The email template body is: 
Flight No: {!Flight__c.Name}
The visualforce page is (embedded into a publisher action):
<apex:page standardController="Flight__c">

    <apex:includeScript value="/soap/ajax/35.0/connection.js"/> 

    <apex:form id="myForm">
        <apex:pageBlock id="myPageblock">

                <script type="text/javascript">
                var query = sforce.connection.query("SELECT Id, Name, Body FROM EmailTemplate WHERE Name = 'myTemplate'");
                var records = query.getArray("records"); 
                var body = '';
                body = records[0].Body;
                document.write('Flight No: {!Flight__c.Name}');


And the rendered VF page is:

What am I doing wrong? It seems like the {!Flight__c...} statements need to be present as hardcoded inside VF for standardcontroller to merge them. Maybe I should follow a different path there, looking forward to your insights.

Thanks in advance.
Best Answer chosen by Tolga Sunar
NagendraNagendra (Salesforce Developers) 
Hi Tolga Sunar,

This is correct behavior.
  • Your first line in the above shows that when you try to output the Body of an EmailTemplate, the merge fields are still literal text.
  • Your second line shows that you can use merge fields in Javascript.
It is probably more straightforward to do a manual merge in Apex. The regex approach isn't terribly complicated, though if you want to support cross-object fields or you merge in data from more than one object, you need to get more fancy.

Here is a basic outline of the steps you can take:

Getting the merge fields :
// create a helper class so you can return more complex information
// each data point contains the merge field to find (e.g. {!Object__c.Field__c})
// and also the field itself to get from the record (e.g. Field__c)
class MergeField
    final String template, field;
    MergeField(String template, String field)
        this.template = template;
        this.field = field;

// accept the template body as input
// yield the merge fields as output
static List<MergeField> getMergeFields(String templateBody)
    List<MergeField> mergeFields = new List<MergeField>();
    Matcher matcher = Pattern.compile('\\{!\\w*\\.\\w*\\}').matcher(templateBody);
    while (matcher.find())
        String template = matcher.group();
        String field = template.substringBetween('.', '}');
        mergeFields.add(new MergeField(template, field));
    return mergeFields;
Helpers :
// you need to avoid NullPointerException if the field has no value
// you can also make sure return type is String
static String safeGet(SObject record, String field)
    Object value = record.get(field);
    return (value == null) ? '' : String.valueOf(value);

// there are two reasons you would get SObjectException
// 1. the merge field is for a different type of SObject
// 2. the merge field has not been queried for
// the latter should be completely avoidable
static String safeMerge(SObject record, MergeField mergeField, String body)
        return body.replace(
            safeGet(record, mergeField.field)
    catch (SObjectException s) { return body; }
Putting it all together :
public with sharing class TemplatePreview
    final List<MergeField> mergeFields;
    public String body { get; private set; }
    public TemplatePreview(String developername)
        this.body = [
            SELECT Body FROM EmailTemplate
            WHERE DeveloperName = :developerName
        this.mergeFields = getMergeFields(body);
    public String mergeTemplate(SObject record)
        for (MergeField mergeField : mergeFields)
            body = safeMerge(record, mergeField, body);
        return body;

    // you do need one more helper to use in your extension
    public List<String> getFields(SObjectType toQuery)
        String comparison = String.valueOf(toQuery);
        for (MergeField mergeField : mergeFields)
            if (mergeField.template.substringBetween('{!', '.') == comparison)
        return fields;

    // helpers from above
Using it in an extension :
public String body { get; private set; }
public MyExtension(ApexPages.StandardController controller)
    TemplatePreview preview = new TemplatePreview('MyTemplate');
    // one of the only remaining use cases for checking if you are in a test
    // you cannot call addFields from a testMethod :(
    if (!Test.isRunningTest())
    this.body = preview.mergeTemplate(controller.getRecord());
Please mark this post as solved so that it gets removed from the unanswered queue which results in helping others who are really in need of it.