Dealing with missing variables
In practice the data-model often has variables that are optional (i.e., sometimes missing). To spot some typical human mistakes, FreeMarker doesn't tolerate the referring to missing variables unless you tell them explicitly what to do if the variable is missing. Here we will show the two most typical ways of doing that.
Note for programmers: A non-existent variable and a variable with null value is the same for FreeMarker, so the "missing" term used here covers both cases.
Wherever you refer to a variable, you can specify a default value for the case the variable is missing, by followin the variable name with a ! and the default value. Like in the following example, when user is missing from data model, the template will behave like if user 's value were the string "Anonymous" . (When user isn't missing, this template behaves exactly like if !"Anonymous" were not there):
| |||
You can ask whether a variable isn't missing by putting ?? after its name. Combining this with the already introduced if directive you can skip the whole greeting if the user variable is missing:
| |||
Regarding variable accessing with multiple steps, like animals.python.price , writing animals.python.price!0 is correct only if animals.python is never missing and only the last subvariable, price , is possibly missing (in which case here we assume it's 0 ). If animals or python is missing, the template processing will stop with an "undefined variable" error. To prevent that, you have to write (animals.python.price)!0 . In that case the expression will be 0 even if animals or python is missing. Same logic goes for ?? ; animals.python.price?? versus (animals.python.price)?? .
-----------------------------------------------------------------------------------------------------------------------
Function/method versus user-defined directive
This is for advanced users again (so ignore it if you don't understand). It's a frequent dilemma if you should use a function/method or an user-defined directive to implement something. The rule of thumb is: Implement the facility as user-defined directive instead of as function/method if:
-
... the output (the return value) is markup (HTML, XML, etc.). The main reason is that the result of functions are subject to automatic XML-escaping (due to the nature of ${... } ), while the output of user-defined directives are not (due to the nature of <@... > ; its output is assumed to be markup, and hence already escaped).
-
... it's the side-effect that is important and not the return value. For example, a directive whose purpose is to add an entry to the server log is like that. (In fact you can't have a return value for a user-defined directive, but some kind of feedback is still possible by setting non-local variables.)
-
... it will do flow control (like for example list or if directives do). You just can't do that with a function/method anyway.
The Java methods of FreeMarker-unaware Java objects are normally visible as methods in templates, regardless of the nature of the Java method. That said, you have no choice there.
----------------------------------------------------------------------------------------------------------------------------------
An FTL tag can't be inside another FTL tag nor inside an interpolation . For example this is WRONG : <#if <#include 'foo'>='bar'>...</#if>
----------------------------------------------------------------
Warning!
A frequent mistake of users is the usage of interpolations in places where it shouldn't/can't be used. Interpolations work only in text sections (e.g. <h1>Hello ${name}!</h1> ) and in string literals (e.g. <#include "/footer/${company}.html"> ). A typical bad usage is <#if ${isBig}>Wow!</#if> , which is syntactically WRONG . You should simply write <#if isBig>Wow!</#if> . Also, <#if "${isBig}">Wow!</#if> is WRONG too, since the parameter value will be a string, and the if directive wants a boolean value, so it will cause a runtime error.
-----------------------------------------------------------------
You can concatenate hashes in the same way as strings, with + . If both hashes contain the same key, the hash on the right-hand side of the + takes precedence.
-----------------------------------------------------------------------------------
Generally, FreeMarker never converts a string to a number automatically, but it may convert a number to a string automatically.
---------------------------------------------------------------------------------
| ||
Assuming that x is 5, it will print:
|
--------------------------------------------------------------------------
User-defined directives can have multiple parameters. For example, add a new parameter color :
| |||
and then you can use this macro like:
| |||
---------------------------------------------------------------------------------------
| |||
The <#nested> directive executes the template fragment between the start-tag and end-tags of the directive. So if you do this:
| |||
the output will be:
|
---------------------------------------------------------------------------------------------
The expressions on both sides of the = or != must evaluate to a scalar. Furthermore, the two scalars must have the same type (i.e. strings can only be compared to strings and numbers can only be compared to numbers, etc.)
--------------------------------------------------------------------------------
There is a little problem with >= and > . FreeMarker interprets the > as the closing character of the FTL tag. To prevent this, you have to put the expression into parenthesis : <#if (x > y)> . Or, you can use > and < on the place of the problematic relation marks: <#if x > y> .
------------------------------------------------------------------------------------------------------
-
Built-ins to use with strings:
-
html : The string with all special HTML characters replaced with entity references (E.g. < with < )
-
cap_first : The string with the first letter converted to upper case
-
lower_case : The lowercase version of the string
-
upper_case : The uppercase version of the string
-
trim : The string without leading and trailing white-spaces
-
-
Built-ins to use with sequences:
-
size : The number of elements in the sequence
-
-
Built-ins to use with numbers:
-
int : The integer part of a number (e.g. -1.9?int is -1 )
${test?html} ${test?upper_case?html}
Assuming that test stores the string ``Tom & Jerry'', the output will be:
----------------------------------------------------------------------------------------Tom & Jerry TOM & JERRY
-
-
Synopsis: unsafe_expr !default_expr or unsafe_expr ! or (unsafe_expr )!default_expr or (unsafe_expr )!
This operator allows you to specify a default value for the case when the value is missing.
A special kind of string literals is the raw string literals. In raw string literals, backslash and ${ have no special meaning, they are considered as plain characters. To indicate that a string literal is a raw string literal, you have to put an r directly before the opening quotation mark or apostrophe-quote. Example:
| |||
will print:
|