Modifiable Lists and Maps
There are cases in a portal theme page or offline packager where it can be beneficial to build up temporary caches of information to be reused or aggregated elsewhere in the page/package. For instance, a package script may want to cache the URLs of various pages as they are built. Unfortunately, Freemarker hashes and sequences are ill-suited to this sort of task.
Sequences and hashes in Freemarker can be created programmatically.
<#assign arr = []/> <#assign hash = {}/>
They can also be updated.
<#assign arr = arr + [newElement]/> <#assign hash = hash + {key: value}/>
However, the Freemarker documentation discourages open-ended concatenation, stating:
and
In fact, in some unusual circumstances with huge collections, exceptions can be thrown when attempting to read from a concatenated hash or sequence.
Titania Delivery provides a set of Freemarker directives or functions that enable the creation and modification of mutable collections that do not suffer from the limitations of sequences and hashes.
newSet
and newList
The newSet
and newList
directives and functions can be
used to instantiate mutable lists of values. The only difference between the two collection
types are:
- Values in sets are unique; attempts to add the same value multiple times will not modify the list.
- Values in lists can be removed by their index via the
removeIndex
directive, which is not available on sets.
Instantiation
Instances of sets and lists are instantiated using the newSet
or
newList
objects. These objects can be invoked as either directives or
functions.
<#-- As a directive --> <@newSet var="mySet"/> <@newList var="myList"/> <#-- As a function --> <#assign mySet = newSet()/> <#assign myList = newList()/>
Once instantiated, the variable can be used as a prefix for the various directives and properties of the collection.
Parameters
var
orassign
- The global variable name to assign the new object. This parameter cannot be passed
to the functional
form.
<@newSet var="mySet"/> <@newSet assign="mySet"/> <#-- Identical to: --> <#assign mySet = newSet()/>
local
- The local variable name to assign the new object. The current processing context
must be within a
<#function>
or<#macro>
. This parameter cannot be passed to the functional form.<@newList local="myList"/> <#-- Identical to: --> <#local myList = newList()/>
from
- Optional. A Freemarker sequence that will be the starting values for the object.
Passed as the first argument to the functional
form.
<@newSet var="mySet" from=['a', 'b', 'c']/> <#assign mySet = newSet(['a', 'b', 'c'])/>
Directives
Sets provide sub-directives that can be used to modify the contents of the set.
add
- Used to add values to the set using the
value
parameter.<@mySet.add value="someValue"/>
clear
- Removes all values from the
collection.
<@myList.clear/>
removeValue
- Removes a value from the collection using the
value
parameter.<@mySet.removeValue value="someValue"/>
removeIndex
(lists only)- Removes a value from a list using the
index
parameter.Important: This directive is not present on sets, and attempts to invoke it on sets will cause errors.<@myList.removeIndex index=4/>
Properties
Sets and lists have the following properties.
size
- The number of elements in the collection.
${mySet.size}
asSequence
- The collection as a native Freemarker sequence. This is the primary mechanism by
which the data in the collection should be read.
Note: There is no meaningful processing or memory overhead when using this property. It is a reference to the underlying storage for the object, it is not a copy.
${myList.asSequence[0]} ${mySet.asSequence?join('<br>')} <#if myList.asSequence?seq_contains('someValue')> <#-- Conditional code here --> </#if>
json
- The set as a JSON
string.
<pre>${mySet.json?html}</pre>
newMap
The newMap
directive and function can be used to instantiate mutable hash
maps. Keys in mutable hashes must be strings.
Instantiation
<#-- As a directive --> <@newMap var="myMap"/> <#-- As a function --> <#assign myMap = newMap()/>
Parameters
var
orassign
- The global variable name to assign the new object. This parameter cannot be passed
to the functional
form.
<@newMap var="myMap"/> <@newMap assign="myMap"/>
local
- The local variable name to assign the new object. The current processing context
must be within a
<#function>
or<#macro>
. This parameter cannot be passed to the functional form.<@newMap local="myMap"/>
from
- Optional. A Freemarker hash that will be the starting entries for the map. Passed
as
the first argument to the functional
form.
<@newMap var="myMap" from={"index": 5, "title": "Some Title"}/> <#assign myMap = newMap({"index": 5, "title": "Some Title"})/>
Directives
Maps provide sub-directives that can be used to modify the contents of the map.
put
- Used to add entries to the map using the
key
andvalue
attributes. Thekey
must be a string. Thevalue
can be anything.<@myMap.put key="someKey" value="someValue"/>
clear
- Removes all entries from the map.
<@myMap.clear/>
remove
- Removes an entry from the set using the
key
parameter.<@myMap.remove key="someKey"/>
Properties
Maps have the following properties.
size
- The number of elements in the map.
${myMap.size}
keys
- The keys in the map as a Freemarker
sequence.
<#if myMap.keys?seq_contains('foo')> <#-- Conditional code here --> </#if>
asHash
- The map as a native Freemarker hash. This is the primary mechanism by which the data
in the map should be read.
Note: There is no significant processing or memory overhead when using this property. It is a reference to the underlying storage for the object, it is not a copy.
${myMap.asHash['someKey']!'No entry for someKey'} <#if myMap.asHash?keys?seq_contains('someKey')> <#-- Conditional code here --> </#if>
json
- The map as a JSON
string.
<pre>${myMap.json?html}</pre>