DocumentEngine expressions are the basic unit of a DocumentEngine template. You can use them alone in a {{mustache}}
, pass
them to a DocumentEngine helper, or use them as values in hash arguments.
DocumentEngine expressions are some contents enclosed by double curly braces {{}}
. In the below template, firstname
is a
variable that is enclosed by double curly braces, which is said to be an expression.
<p>{{firstname}} {{lastname}}</p>
If the below input object is applied to the template
{
firstname: "Yehuda",
lastname: "Katz",
}
Expressions are compiled to produce the output as follows:
<p>Yehuda Katz</p>
DocumentEngine expressions can also be dot-separated paths.
{{person.firstname}} {{person.lastname}}
This expression looks up the person
property in the input object and in turn looks up the firstname
and lastname
property within the person
object.
Pass the below input object to the template
{
person: {
firstname: "Yehuda",
lastname: "Katz",
},
}
Output will be generated as below
Yehuda Katz
DocumentEngine also supports a deprecated /
syntax, so you could write the above template as:
{{person/firstname}} {{person/lastname}}
Some helpers like #with
and #each
allow you to dive into nested objects. When you include ../
segments in your
path, DocumentEngine will change back into the parent context.
{{#each people}}
{{../prefix}} {{firstname}}
{{/each}}
Even though the name is printed while in the context of a comment, it can still go back to the main context (the root-object) to retrieve the prefix.
WARNING
The exact value that ../
will resolve to varies based on the helper that is calling the block. Using ../
is only
necessary when context changes. Children of helpers such as {{#each}}
would require the use of ../
while children of
helpers such as {{#if}}
do not.
{{permalink}}
{{#each comments}}
{{../permalink}}
{{#if title}}
{{../permalink}}
{{/if}}
{{/each}}
In this example all of the above reference the same prefix value even though they are located within different blocks.
This behavior is new as of DocumentEngine 4; the
release notes
Identifiers may be any unicode character except for the following:
Whitespace !
"
#
%
&
'
(
)
*
+
,
.
/
;
<
=
>
@
[
\
]
^
`
{
|
}
~
In addition, the words true
, false
, null
and undefined
are only allowed in the first part of a path expression.
To reference a property that is not a valid identifier, you can use segment-literal notation, [
. You may not include a
closing ]
in a path-literal, but all other characters are allowed.
JavaScript-style strings, "
and '
, may also be used instead of [
pairs.
{{!-- wrong: {{array.0.item}} --}}
correct: array.[0].item: {{array.[0].item}}
{{!-- wrong: {{array.[0].item-class}} --}}
correct: array.[0].[item-class]: {{array.[0].[item-class]}}
{{!-- wrong: {{./true}}--}}
correct: ./[true]: {{./[true]}}
In DocumentEngine, the values returned by the {{expression}}
are HTML-escaped. Say, if the expression contains &
, then
the returned HTML-escaped output is generated as &
. If you don't want DocumentEngine to escape a value, use the
"triple-stash", {{{
:
In the below template, you can learn how to produce the HTML escaped and raw output.
raw: {{{specialChars}}}
html-escaped: {{specialChars}}
Pass the special characters to the template
{ specialChars: "& < > \" ' ` =" }
Expressions enclosed by "triple-stash" ({{{
) produce the raw output. Otherwise, HTML-escaped output is generated as
below.
raw: & < > " ' ` =
html-escaped: & < > " ' ` =
Template whitespace may be omitted from either side of any mustache statement by adding a ~
character by the braces.
When applied all whitespace on that side will be removed up to the first DocumentEngine expression or non-whitespace
character on that side.
{{#each nav ~}}
<a href="{{url}}">
{{~#if test}}
{{~title}}
{{~^~}}
Empty
{{~/if~}}
</a>
{{~/each}}
with this context:
{
nav: [{ url: "foo", test: true, title: "bar" }, { url: "bar" }];
}
results in output sans newlines and formatting whitespace:
<a href="foo">bar</a><a href="bar">Empty</a>
This expands the default behavior of stripping lines that are "standalone" helpers (only a block helper, comment, or partial and whitespace).
{{#each nav}}
<a href="{{url}}">
{{#if test}}
{{title}}
{{^}}
Empty
{{/if}}
</a>
{{~/each}}
will render
<a href="foo">
bar
</a>
<a href="bar">
Empty
</a>
DocumentEngine content may be escaped in one of two ways, inline escapes or raw block helpers. Inline escapes created by
prefixing a mustache block with \
. Raw blocks are created using {{{{
mustache braces.
\
{{{{raw}}}}
{{escaped}}
{{{{/raw}}}}
Raw blocks operate in the same manner as other block helpers with the distinction of the child content is treated as a literal string.
Merge fields let you pull Salesforce data directly into your templates. They support:
{{:Opportunity.:Owner.:Name}}
){{::labels.*}}
date
, currency
, formatNumber
Use the colon-prefixed path to bind Salesforce fields. Labels are available via ::labels
for i18n.
{{::labels.Company_Name}}: {{:BillingName}}
{{::labels.Quote_Number}}: {{:QuoteNumber}}
Traverse parent/child relationships by chaining segments. Use .:
to step through related objects.
{{::labels.Prepared_By}}: {{:Opportunity.:Owner.:Name}}
{{::labels.Prepared_By_Email}}: {{:Opportunity.:Owner.:Email}}
TIP
You can combine relationship paths with helpers. For example, format dates from the base record or a related record using date
.
Iterate related lists (e.g., {{#each :QuoteLineItems}}
) using {{#each}}
. Inside the loop, fields resolve in the row context.
<table class="product-table">
<thead>
<tr>
<th>{{::labels.Product_}}</th>
<th>{{::labels.Quantity_}}</th>
<th>{{::labels.Price_}}</th>
<th>{{::labels.Total_}}</th>
</tr>
</thead>
<tbody>
{{#each :QuoteLineItems}}
<tr>
<td>{{:Product2.:Name}}</td>
<td>{{:Quantity}}</td>
<td>{{currency :UnitSalesPrice__c "USD"}}</td>
<td>{{currency :TotalPrice "USD"}}</td>
</tr>
{{/each}}
</tbody>
</table>
WARNING
When you are inside an {{#each}}
block, use ../
to access parent context values (such as totals or flags on the parent record).
{{#each :QuoteLineItems}}
Row Total: {{currency :TotalPrice "USD"}} — Quote Grand Total: {{currency ../:GrandTotal "USD"}}
{{/each}}
Use {{#if}}
and logic helpers to render only when values exist.
{{#if (or :BillingStreet :BillingCity :BillingCountry)}}
<strong>{{::labels.Billing_Address}}</strong><br>
{{:BillingStreet}}<br>
{{:BillingCity}}, {{:BillingState}} {{:BillingPostalCode}}, {{:BillingCountry}}
{{/if}}
Merge fields work with built-in helpers for dates, currency, and numbers.
{{::labels.Created_Date}}: {{date :CreatedDate 'MMM DD, YYYY'}}
{{::labels.Expiration_Date}}: {{date :ExpirationDate 'MMM DD, YYYY'}}
Unit Price: {{currency :UnitSalesPrice__c "USD"}}
Discount: {{formatNumber :Discount '0.00'}}%
Grand Total: {{currency :GrandTotal "USD"}}
Filter and count items in related lists with selectors and conditions.
{{!-- List all product names --}}
{{#each :QuoteLineItems}}
{{:Product2.:Name}}<br>
{{/each}}
{{!-- If any line item has Product2.Name > "Chat Bot" (lexicographically) show special conditions --}}
{{#if (select :QuoteLineItems 'Product2.Name' '$>' 'Chat Bot')}}
{{::labels.Chatbot_Conditions}}
{{/if}}
A compact quote header demonstrating labels, fields, relationships, conditionals, and formatting:
<table class="quote-header">
<tbody>
<tr>
<th>{{::labels.Company_Name}}</th>
<td>{{:BillingName}}</td>
</tr>
{{#if (or :BillingStreet :BillingCity :BillingCountry)}}
<tr>
<th>{{::labels.Billing_Address}}</th>
<td>
{{:BillingStreet}}<br>
{{:BillingCity}}, {{:BillingState}} {{:BillingPostalCode}}, {{:BillingCountry}}
</td>
</tr>
{{/if}}
<tr>
<th>{{::labels.Created_Date}}</th>
<td>{{date :CreatedDate 'MMM DD, YYYY'}}</td>
</tr>
<tr>
<th>{{::labels.Prepared_By}}</th>
<td>{{:Opportunity.:Owner.:Name}}</td>
</tr>
<tr>
<th>{{::labels.Prepared_By_Email}}</th>
<td>{{:Opportunity.:Owner.:Email}}</td>
</tr>
<tr>
<th>{{::labels.Quote_Number}}</th>
<td>{{:QuoteNumber}}</td>
</tr>
<tr>
<th>{{::labels.Expiration_Date}}</th>
<td>{{date :ExpirationDate 'MMM DD, YYYY'}}</td>
</tr>
</tbody>
</table>
<br>
<table class="product-table">
<thead>
<tr>
<th style="text-align:left;width:15%">{{::labels.Product_}}</th>
<th style="text-align:left">{{::labels.Quantity_}}</th>
<th style="text-align:center">{{::labels.Price_}}</th>
<th>{{::labels.Total_}}</th>
</tr>
</thead>
<tbody>
{{#each :QuoteLineItems}}
<tr>
<td style="text-align:left">{{:Product2.:Name}}</td>
<td style="text-align:center">{{:Quantity}}</td>
<td>{{currency :UnitSalesPrice__c "USD"}}</td>
<td>{{currency :TotalPrice "USD"}}</td>
</tr>
{{/each}}
</tbody>
</table>
<br>
<div class="quote-subtotal" style="width:50pt;">
{{currency :GrandTotal "USD"}}
</div>
<div class="quote-subtotal" style="width:150pt">
{{::labels.Grand_Total}}
</div>