[TODO: This section is under rewriting and is incomplete!]
As we have described, a template can use the variables defined in the data-model. A template can also define variables outside the data-model for its own use. These temporary variables can be created and replaced using FTL directives. Note that each template processing job has its own private set of these variables that exists while the given page is being rendered. This variable set is initially empty, and will be thrown away when the template processing job has been finished.
You access a variable that you have defined in the template exactly as if it were a variable in the data-model root. The variable has precedence over any variable of the same name defined in the data model. That is, if you define a variable called ''foo'' and coincidentally, there is a ''foo'' in the data-model as well, then the variable created in the template will hide (not overwrite!) the variable in the data-model root. For example, ${foo} will print the value of the variable created in the template.
For information about syntax of variable references please read: Template Author's Guide/Expressions
We have two new directives, set and var, which deprecate assing/local/global. At the first glance the set directive is the same as assign; [#set x = 1] has the same effect as [#assign x = 1]. But, with the var directive you can declare a variable in the lexical scope of the block where it occurs, and set will set the variable in the innermost scope that declared the variable (while assign always created/modified the variable on the top-level, i.e., in the "main namespace"). This for example can be utilized to create local variables in macros (hence the local directive is now deprecated):
| |||
which will print:
| |||
Note that the var directive can also specify the initial value, so earlier we could write just:
| |||
The var directive can declare variables in arbitrary blocks, not only in macros. This was no possible at all in 2.3. Example:
| |||
This prints:
| |||
Of course instead of if directive we could use list as well, or even user-defined directives. It works with all. But of course it doesn't consider HTML tags, since that's just static text for FreeMarker, not tags.
Now a few example to explain some marginal cases and answer common questions and misunderstandings:
-
Variables created with var will be visible only from the places that are inside the relevant block in the template file. If it sounds heavy, it's just the same thing as with local variables in virtually all languages. Example:




[#macro myMacro] In myMacro: ${x} [#set x = "Outer modified"] [/#macro] [#set x = "Outer"] ${x} [#if true] [#var x = "Inner"] ${x} [@myMacro /] ${x} [/#if] ${x}



Output:




Outer Inner In myMacro: Outer Inner Outer modified



A marginal rule regarding lexical scoping is that the variables are, in fact, visible only between the part of the template file that's between the var and the block closing FTL tag:




[#set x = '*'] [#list 1..3 as i] [#-- loops three times --] ${x} [#set x = x + '*'] [#var x = "Inner"] ${x} [/#list]



Output:




* Inner ** Inner *** Inner



-
If you don't specify the initial value in var, that's the same as writing [#var x = null] (note: supporting null is a new feature in 2.4). Reading the null will not cause fall-back to higher scopes because the variable exists, only it stores a null as its value. For example:




${x!'Missing'} [#set x = "Top level"] ${x!'Missing'} [#if true] [#var x] ${x!'Missing'} [#-- Here! --] [#set x = "Inner"] ${x!'Missing'} [/#if] ${x!'Missing'}



Output:




Missing Top level Missing Inner Top level



-
The var directive can be used on the top level, i.e., outside all bocks. In that case it behaves as if the whole template were in an imaginary block. This has importance only when you include that template in another template, since then the variable will not be visible from the including template.
-
To achieve the same effect as [#global x = 1], you can write [#set x = 1 in .globals]. Sure, the old way was much nicer, so if you set globals a lot, you may should stick with the old way of doing it. (But we think using globals at many places is a bad practice usually, so we don't want to encourage new users to do it.)


