Document last updated 10 April 2001.
We are very interested in feedback that would make these materials better. Feel free to write the author, Jonathan Revusky.

Este documento en español
Ce document en français

Exploring Template Variables

You will recall that in the "Hello, Niggle" example, our execDefault() method exposed two template variables which were simply strings -- or scalars in template-speak. While this might have seemed like a big step compared to completely static HTML pages, it is really only a very small feature of what we can do with the built-in template system, which allows us to dynamically expose complex data structures made up of lists and hashes-- as well as scalars.

This application contains 3 page templates. The entries.nhtml template displays all the guestbook entries. The add.nhtml template contains a form which allows the user to add a guestbook entry. The thanks.nhtml simply thanks the user for her comments, after processing the form. Take a look at entries.nhtml. As we pointed out in the first example, freemarker templates use the ${...} as an escape syntax, meaning that the strings within that ${...} block are interpreted in a special way -- as template variables.

The entries.nhtml also introduces a directive that is specific to Freemarker. Look at the line:

<list entries as entry>

This assumes the presence of a list type variable called entries. Now, a scalar variable, since it is simply a string, is typically used directly as page content via the ${...} escape syntax. By contrast, what you do with a list variable, such as entries in this case, is that you iterate over its elements. This is what that directive <list entries as entry> is saying. The template code within that list block is repeated n times where n is the number of elements in the list. The entry variable in the block represents the current nested variable that we are iterating over.

What further adds interest to this example is that the elements of the entries list are themselves hashes, with their own subvariables, which finally are scalars. So finally, the various subvariables in the entry hash are used directly in the page via the ${...} syntax, e.g. ${entry.name} and so on.

The Java side

Now that you have eyeballed the entries template, take a look at the corresponding java code in GuestbookServletInteraction.java. Look at the execEntries() method. It's incredibly brief.


    public void execEntries() throws IOException {
        this.page = getPage("entries.nhtml");
        page.expose("entries", entries); // expose the list of entries to the page.
    }
    

Actually, the code for this servlet is surprisingly terse. The most involved method is execProcess() which processes the CGI variables sent by the form in the add.nhtml template. If no name was specified, it exposes an error variable. Otherwise, it creates a hashtable containing the subvariables that make up the guestbook entry and adds it to the static entries list.

Note that the exposeDefaultVariables method provides a convenient hook to define variables that are always exposed independently of which execXXX method was invoked.

Conclusions

Even though this guestbook is primitive, since it does not deal with persistence of data, it does a surprising amount with very little code. This is achieved mostly due to our ability to expose a complex data structure to the page template at one go. In this case, we were able to drop a list -- which in turn contained hashes -- onto the page and unroll all of the nested content for display. And this required very very little java code to be written. You will realize also that we can nest lists and hashes to an arbitrary level of complexity! We could have a list of lists that in turn contain hashes that contain further lists!

Since all of the code -- including both the java side and the freemarker templates -- is little over 100 lines, it should be feasible to study the example and fully understand all of its various elements.

I would encourage you to make small changes to the code and templates and observe the changes. This will reinforce what you have learned. When you are comfortable with this example, I would encourage you to move on to the next example, the mini-rolodex.