Freemarker Tips and Tricks

Freemarker is a well-documented server-side templating engine for generating text output. Titania Delivery utilizes it to generate the HTML for Portal pages. There are several constructs and patterns that are commonly used in Portal Themes that are posted here for reference.
Declaring the Titania Delivery Tag Library

In order to use the Titania Tag Library, the following must be included at the top of the template.

<#assign td=JspTaglibs['http://www.titaniasoftware.com/harp/taglib']/>
Includes

Freemarker allows for the modular development of HTML pages. Smaller templates can be combined together to make a full page. To include one template in another, add the following to the destination template, wherever you want the target template to be included:

<#include "path/to/template.ftl" />
Page Variables

Titania Delivery populates the templates with a model consisting of many variables. These variables can be accessed via:

${propertyName.fieldName}
Escapes

It is strongly advised to escape the text received from a data model. Freemarker provides a number of built-in functions to accomplish this. This allows Freemarker to format text in a manner that the destination is expecting. For example, it can escape special characters for insertion into the html page, or format a String so that it can be used as a JavaScript variable. To escape data that will be output directly to a page, use:

${propertyName.fieldName?html}

To escape data passed into JavaScript strings, use:

${propertyName.fieldName?js_string}

For example:

<script>
  var portalTitle = "${portal.title?js_string}";
</script>
Comments

You can mark comments in your template that will not be rendered to the HTML using: <#-- and -->.

<#-- This is a comment. -->
Conditional Processing

Freemarker supports conditional processing via the <#if>, <#else>, and <#elseif> expressions.

<#if condition1>
...
<#elseif condition2>
...
<#else>
...
</#if>
Loops

You can iterate over arrays of values using <#list>.

<ul>
  <#list array as value>
    <li>${value_index} - ${value?html}</li>
  </#list>
</ul>

When iterating through a list, a number of special values become available.

${item_index}
The numerical index within the array of the current entry.
${item_has_next}
A boolean value indicating whether there is another value in the list.
Data Existence

It is sometimes the case that a data model may or may not exist on a page. In these instances, the template must check for their existence before referencing them. This can be accomplished via:

${propertyName.fieldName??}

which returns a boolean value. For example:

<#if modelName.fieldName??>
  ${propertyName.fieldName?html}
<#else>
  <b>No Value!</b>
</#if>
Important: If a Freemarker template attempts to reference a field that is not present, an error message will be rendered at the location of the error, and further rendering will halt, resulting in a broken page. You should always check for the existence of optional properties before attempting to render them.
Default Values

In cases where a default value is available, you can avoid using <#if> by using the default value operator (!).

${propertyName.optionalProperty!"Default Value"}
Attempt/Recover

Often, if there is an error in a template, the page can fail to render entirely, without an error message that could help track down the error. You can alleviate this problem by wrapping part of a template, or even the whole template, in an <#attempt> block, using <#recover> to report any errors.

<#attempt>
<#-- code here -->
<#recover>
ERROR: <pre>${.error?html}</pre>
</#attempt>

If a Freemarker error occurs inside the <#attempt> block, the code after the <#recover> tag will be executed instead, and you can access the error via the .error variable.

Assigning Custom Model Properties

Freemarker templates can declare custom properties using the <#assign> directive. For example:

<#assign customProperty="some value"/>

Or

<#assign customMarkupSnippet>
  <p>Markup Snippet</p>
</#assign>

You can then use the custom model property the same way as you would any other. With the above declarations, this template:

<p>Custom property: ${customProperty?html}</p>
${customMarkupSnippet}

would result in the following markup:

<p>Custom property: some value</p>
<p>Markup Snippet</p>
Passing Parameters to Included Modules

The properties declared using <#assign> are made available for the rest of the page, and remain in effect when processing template language referenced via <#include>. You can use this fact to parameterize behavior in reused template modules. For example, you could have the following in a reused module:

<#-- If trigger is defined and true -->
<#if trigger?? && trigger>
  Optional Stuff
</#if>

In a template using this module, you could assign 'trigger' to true to enable the optional behavior.

<#assign trigger=true>
<#include "otherModule.ftl"/>
Macros

Freemarker allows for creating additional user-defined directives called macros; essentially a reusable template fragment assigned to a variable. For instance, the following macro could be defined:

<#macro greet>
  <#if user??>
    <p>Hello, ${user.userName}</p>
  <#else>
    <p>Hello, Titania Delivery</p>
  </#if>
</#macro>

Later in the template (or in any template that includes a template with the above macro definition), the following could be used to execute the macro:

<@greet/>