Velocimacro – Generate a HTML Select box and its Options

A quick and simple Velocimacro to generate HTML Select boxes and its Options; automatically selects the correct option based on the value given.

You can place this #macro anywhere in your Velocity templates but I used my global VM_global_library.vm file.

Code

CODE:
  1. #macro( generateSelectBox $name $options $value )
  2. <select name='$name' value='$value'>
  3. #foreach ( $option in $options )
  4.   #set( $selected = "" )
  5.   #if ( $option == $value )
  6.     #set( $selected = "selected='true'" )
  7.   #end
  8.   <option value='$option' $selected>$option</option>
  9. #end
  10. </select>
  11. #end

Example Usage

CODE:
  1. #generateSelectBox( "enabled" ["Y","N"] $form.enabled )

The resulting HTML:

CODE:
  1. <select name='enabled' value='N'>
  2.   <option value='Y'>Y</option>
  3.   <option value='N' selected='true'>N</option>
  4. </select>

Addendum

11th November 2005 : Thanks to MATT for pointing out the FreeMarker template engine as a promising replacement for Velocity. ;)

Velocity if statement is type sensitive…

Problem

I discovered that comparisons in Velocity if statements are type-sensitive the hard way.

For example, I am trying to display the 'selected' option in a html <SELECT> object. The list of possible values is $list, each is a simple 'NameValuePair' value object { String name, String value }.

The object I am editing in this form is $obj, and the field I am testing against is $obj.typeId defined as a long.

CODE:
  1. <select name='typeId' value='$!{obj.typeId}'>
  2. #foreach ( $item in $list )
  3.   #if ( $item.value == $obj.typeId )
  4.     <option value='$item.value' selected='true'>$item.name</option>
  5.   #else
  6.     <option value='$item.value'>$item.name</option>
  7.   #end
  8. #end
  9. </select>

However, the if statement on line 3 is actually comparing a String to a long which are of course never going to be equal.

Solution

The easiest work around in this case was to convert the $obj.typeId into a String before the comparison.

CODE:
  1. <select name='typeId' value='$!{obj.typeId}'>
  2. #set ( $typeId = "$!{obj.typeId}" )
  3. #foreach ( $item in $list )
  4.   #if ( $item.value == $typeId )
  5.     <option value='$item.value' selected='true'>$item.name</option>
  6.   #else
  7.     <option value='$item.value'>$item.name</option>
  8.   #end
  9. #end
  10. </select>

Any comments / feedback welcomed ;)

Velocity Templates and Newlines

If you're reading this article you've probably encounted the same problem as I have. I was trying to put a newline '\n' character in the value of a variable in a Velocity template.

Attempt 1:

I assumed \n would work...

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.\nPlease do something about it." )
  3. #end

This produced There was no foo set in the Context.\nPlease do something about it. as the value of $foo.

Attempt 2:

I just thought this was worth a shot :D

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.
  3. Please do something about it." )
  4. #end

And the template failed to compile

Solution:

Basically, the easiest way I found is to place the newline, carriage return or other special character in the context.

JAVA:
  1. public Template handleRequest( HttpServletRequest request, HttpServletResponse response, Context context )
  2. {
  3.     ...
  4.  
  5.     context.put( "nl", "\n" );
  6.     context.put( "cr", "\r" );
  7.  
  8.     ...
  9. }

And in your template:

CODE:
  1. #if ( !$foo )
  2.   #set ( $foo = "There was no foo set in the Context.${nl}Please do something about it." )
  3. #end

Maybe not the best solution but it works for me. If you expect to use it across your entire application I suggest you override VelocityServlet.createContext in your Servlet to add these characters to every context in your application.

Example:

JAVA:
  1. protected Context createContext( HttpServletRequest request, HttpServletResponse response ) {
  2.     Context context = super.createContext( request, response );
  3.    
  4.     context.put( "nl", "\n" );
  5.     context.put( "cr", "\r" );
  6.    
  7.     return context;
  8. }