5. Directives

References allow template designers to generate dynamic content for web sites, while Directives permit web designers to truly take charge of the appearance and content of the web site. A directive is a script element that can be used to manipulate the rendering of the template.

As described in Chapter 3.1, Velocity Directives are part of either single or multi-line statements and are preceded by a hash sign (#). While the hash sign is technically not part of the directive, we will still speak about the #if or #set directive.

Velocity knows about the following directives:[7]

5.1 The #set directive

The #set directive is used for setting the value of a reference. It is used in a single-line statement.

A value can be assigned to either a variable reference or a property reference.

Example 5.1. Value assignment using the set directive

## Assigning a variable value
#set( $fruit = "apple" )

## Assigning a property value
#set( $customer.Favourite = $fruit )

The left hand side (LHS) of the assignment must be a variable reference or a property reference. The right hand side (RHS) can be one of the following types:

  • Variable reference

  • String literal

  • Property reference

  • Method reference

  • Number literal

  • List

  • Map

  • Expression

Example 5.2. Valid reference assignments

## variable reference
#set( $fruit = $selectedFruit )

## string literal
#set( $fruit.flavor = "sweet" )

## property reference
#set( $fruit.amount = $cart.total )

## method reference
#set( $fruit.color = $colorlist.selectColor($select) )

## number literal
#set( $fruit.value = 123 )

## List
#set( $fruit.sorts = ["Apple", "Pear", "Orange"] )

## Map
#set( $fruit.shapes = {"Apple" : "round", "Pear" : "conical"}) 

[Note]Note

For the List example the elements defined with the [..] operator are accessible using the methods defined in the java.util.List class. So, for example, you could access the first element above using $fruit.sorts.get(0).

Similarly, for the Map example, the elements defined within the {..} operator are accessible using the methods defined in the java.util.Map class. So, for example, you could access the first element above using $fruit.shapes.get("Apple") to return the String round, or even $fruit.shapes.Apple to return the same value.

The RHS can also be an arithmetic expression as described in the Math chapter below.

Example 5.3. Expression examples

#set( $value = $foo + 1 )
#set( $value = $bar - 1 )
#set( $value = $foo * $bar )
#set( $value = $foo / $bar )

Assigning null values to references

In its default configuration, Velocity treats null values on the RHS special. If your developers don't change the default configuration, you must understand that it is not possible to assign a null value through a set directive to a reference. Starting with Velocity 1.5, a runtime property (directive.set.null.allowed) exists that removes this restriction. If you do not want null values to be treated special, tell your application developers that they should look up this property in the Velocity Developers Guide and set it to true.

[Note]Note

Removing this restriction is one of the new features of Velocity 1.5. If you are maintaining existing template code from older Velocity versions, you probably want to keep the old behaviour.

For new developments based on Velocity 1.5 and beyond, we strongly recommend that you don't treat null values on the RHS special (set directive.set.null.allowed to be true). This will be the default behaviour in future Velocity versions.

The remainder of this chapter assumes that you kept the default configuration of Velocity.

If the RHS is a property or method reference that evaluates to null, it will not be assigned to the LHS and the LHS will not be altered. This is very different from the behaviour in e.g. the Java programming language and needs some discussion.

In the following piece of code, two queries are executed using the same set of template references:

#set( $result = $query.criteria("fruit") )
The result of the first query is $result

#set( $result = $query.criteria("customer") )
The result of the second query is $result

If $query.criteria("name") returns the string "apple", and $query.criteria("customer") returns null, the above VTL will render as the follows:

The result of the first query is apple

The result of the second query is apple

In the second set directive, the RHS is null, because $query.criteria("customer") returned null. So the RHS will not be modified (and the old value retained).

Unfortunately, this can lead to hard-to-detect errors, for example with #foreach loops that attempt to change a reference using a #set directive, then immediately test that reference with an #if directive:

#set( $criteria = ["fruit", "customer"] )

#foreach( $criterion in $criteria )

  #set( $result = $query.criteria($criterion) )

  #if( $result )
    Query was successful
  #end

#end

In the above example, it would not be wise to rely on the evaluation of $result to determine if a query was successful. After $result has been set (added to the context), it cannot be set back to null (removed from the context).

One solution to this would be to reset the value of $result in every loop iteration:

#set( $criteria = ["name", "address"] )

#foreach( $criterion in $criteria )

  #set( $result = "" )
  #set( $result = $query.criteria($criterion) )

  #if( $result != "" )
    Query was successful
  #end

#end

However, the easiest way is to use the quiet reference notation:

#set( $criteria = ["name", "address"] )

#foreach( $criterion in $criteria )

  #set( $result = $!query.criteria($criterion) )

  #if( $result != "" )
    Query was successful
  #end

#end

If the query fails, $result gets the empty string assigned.

String Literals

When using the #set directive, string literals that are enclosed in double quote characters will be parsed and rendered, as shown:

#set( $directoryRoot = "www" )
#set( $templateName = "index.vm" )
#set( $template = "$directoryRoot/$templateName" )
$template

The output will be

www/index.vm

However, when the string literal is enclosed in single quote characters, it will not be parsed:

#set( $fruit = "apple" )
$fruit

#set( $veggie = '$fruit' )
$veggie

This renders as:

apple

$fruit

By default, rendering unparsed text using single quotes is activated in Velocity. This default can be changed by changing the runtime.interpolate.string.literals property to be false. (See the Velocity Developers Guide for more information).



[7] If is possible to add custom directives through the Velocity configuration. These are merely the directives shipped with the default Velocity configuration. It is even possible to turn some of these off.