type safe templating

Previous Tutorial contents Next

Jamon Tutorial - 8. Template Fragments

  1. Passing fragment arguments In addition to template arguments, Jamon allows passing a block, or "fragment," of Jamon text to a template. When passing a template fragment, the invocation syntax must look like <&| target; arg1 = ... &> [fragment of Jamon text] </&>, and any template content after the start tag, <&| target; arg1 = ... &>, up to the closing tag, </&>, is considered the fragment argument.

    In this example, FragmentCallerTemplate.jamon,

    <%args>
      String userName;
    </%args>
    <%doc>Output list of links</%doc>
    Site map:<br>
    <ul>
    <&| liRef; href = "/about.html" &>About this company </&>
    <&| liRef; href = "/privacy.html" &>We protect your information </&>
    <&| liRef; href = "/stores.html" &>Find the store nearest you! </&>
    <%if userName != null %>
      <&| liRef; href = "/accountInfo.html" &>
        Account information for <% userName %>
      </&>
    </%if>
    </ul>
    
    <%def liRef>
      <%frag content/>
      <%args>
        String href;
      </%args>
      <li><a href="<% href %>"><& content &></a></li>
    </%def>
    
    the block of HTML text "Account information for <% userName %>" is passed to the subtemplate liRef, which constructs a list item with an HTML anchor using the fragment text as the anchor text.

    In this example the text passed to the subtemplate includes an emit statement, <% userName %>. This emit statement is evaluated in the subtemplate. The subtemplate has access to all arguments passed to the calling template as well as final and class scope fields in the calling template. Unfortunately, however, any non-final variable declared in the Jamon text will not be visible to the called template that evaluates the template fragment.

    The advantage of framgments is that the author can compose the text to display in the main template, but then pass that text to another template to process. In this example, the author specifies the text to include in the link, but passes the text to a subtemplate to encapsulate in the HTML tags required to build the link.

    A template fragment is translated by Jamon into an inner class of the template that contains the fragment text. This means that the only variables in the containing template that can be accessed by fragment text are
    • class scope variables declared within <%class></%class> tags
    • final variables and arguments to the template. (Note that all arguments to the template are implemented as final fields in the translated Java class and, hence, are visible to inner classes.)
  2. Accepting fragment arguments A template declares that it accepts template fragments by including the <%frag fragmentName/> tag. The fragmentName argument is the name of the fragment template. The template that accepts the fragment calls the fragment as it would any other template to output its contents.

    The template below, LiRef.jamon, is a more elaborate version of the subtemplate in the above example.

    <%frag content/>
    <%args>
      String href;
      String style = null;
    </%args>
    <li>
      <a href="<% href %>"<%if style != null %> class="<% style %>"</%if>><& content &></a>
    </li>
    
    It formats the content fragment text with the specified stylesheet style as an HTML anchor inside a list item.
  3. Parameterized Template Fragments A template fragment is a template and can have arguments just like a template.

    To add arguments to a fragment, simply include a <%args> ... </%args> tag at the beginning of the fragment.

    <%java DateFormat dateFormat = new SimpleDateFormat("MM/dd"); %>
    We offer the following holidays:
    <&| AlternatingList; items = holidays.iterator() &>
      <%args>
        Object holidayObj;
      </%args>
      Holiday holiday = (Holiday) holidayObj;
      <td><% dateFormat.format(holiday.getDate()) %></td>
      <td><% holiday.getName() %></td>
    </&>
    
    This fragment expects a single holidayObj argument to be provided each time it is invoked.
    The signature of the arguments to the fragment, that is the types of the arguments and their order, must match the signature of the fragment arguments as defined in the template that accepts the fragment.

    To declare a template that expects a fragment with arguments, just add parameters within the <%frag name> parameters </%frag> tag. Thus a <%frag name>...</%frag> is similar to a <%args>...</%args> except it has a name and its parameters cannot have default values.

    <%import>
      java.util.Iterator;
    </%import>
    <%frag content>
      Object renderable;
    </%frag>
    <%args>
      Iterator items;
    </%args>
    <%java int row = 0; %>
    <table>
    <%while items.hasNext() %>
        <tr bgcolor="<% row++ % 2 == 0 ? "white" : "grey" %>">
          <& content; renderable = items.next() &>
        </tr>
    </%while>
    </table>
    
    This template, AlternatingList.jamon, loops through all the objects that were passed to it by the items Iterator, and assigns each one in turn to the fragment parameter renderable when it calls the template fragment. By using a template fragment, AlternatingList can format a table to have rows with alternating background colors and yet can execute the fragment's block of Jamon code to fill in each row.

  4. A Template Fragment Example The template FragmentExampleTemplate.jamon, below, produces a table listing the name and date of the holidays recognized by the template author. The template formats the row it would like to see for each line of output, and then passes this fragment of Jamon text to the AlternatingList template to format into a table with alternating background colors.

    <%import>
      java.text.DateFormat;
      java.text.SimpleDateFormat;
      java.util.List;
      java.util.Iterator;
    </%import>
    
    <%args>
      List holidays;
    </%args>
    
    <%doc>
    dateFormat MUST be declared final so the fragment can access it.
    </%doc>
    <%java final DateFormat dateFormat = new SimpleDateFormat("MM/dd"); %>
    We offer the following holidays:
    <&| AlternatingList; items = holidays.iterator() &>
      <%args>
        Object holidayObj;
      </%args>
    <%java  Holiday holiday = (Holiday) holidayObj; %>
      <td><% holiday.getName() %></td>
      <td><% dateFormat.format(holiday.getDate()) %></td>
    </&>
    

    The example template is executed by the Holiday.java Java class.

    import java.io.OutputStreamWriter;
    import java.util.List;
    import java.util.ArrayList;
    import java.util.Date;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    
    public class Holiday {
      private Date date;
      private String name;
    
      static private DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    
      public Holiday (String p_name, Date p_date) {
        name = p_name;
        date = p_date;
      }
    
      public String getName() { return  name; }
      public Date getDate() { return  date; }
    
      public static void main(String[] argv) throws Exception {
        List<Holiday> holidays = new ArrayList<Holiday>();
        holidays.add(new Holiday("New Year's", format.parse("2003-1-1")));
        holidays.add(new Holiday("July 4", format.parse("2003-7-4")));
        holidays.add(new Holiday("Thanksgiving", format.parse("2003-11-17")));
        holidays.add(new Holiday("Christmas", format.parse("2003-12-25")));
        new FragmentExampleTemplate()
          .render(new OutputStreamWriter(System.out), holidays);
      }
    }
    

    The output from the template is

    We offer the following holidays:
    <table>
    
        <tr bgcolor="white">
          
      <td>New Year's</td>
      <td>01/01</td>
    
        </tr>
    
        <tr bgcolor="grey">
          
      <td>July 4</td>
      <td>07/04</td>
    
        </tr>
    
        <tr bgcolor="white">
          
      <td>Thanksgiving</td>
      <td>11/17</td>
    
        </tr>
    
        <tr bgcolor="grey">
          
      <td>Christmas</td>
      <td>12/25</td>
    
        </tr>
    
    </table>
    
    
Previous Tutorial contents Next