Jamon Tutorial - 8. Template Fragments
- 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
, and any template content after the start tag,<&| target; arg1 = ... &> [fragment of Jamon text] </&>
, up to the closing tag,<&| target; arg1 = ... &>
</&>
, 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 subtemplateliRef
, 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.)
-
class scope variables declared within
- Accepting fragment arguments
A template declares that it accepts template fragments by including
the
<%frag fragmentName/>
tag. ThefragmentName
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 thecontent
fragment text with the specified stylesheet style as an HTML anchor inside a list item. - 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
tag at the beginning of the fragment.<%args>
...</%args>
<%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 singleholidayObj
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
tag. Thus a<%frag name> parameters </%frag>
is similar to a<%frag name>
...</%frag>
except it has a name and its parameters cannot have default values.<%args>
...</%args>
<%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 , and assigns each one in turn to the fragment parameteritems Iterator
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. - 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 theAlternatingList
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>