| <chapter id="built-ins"> |
| <title>Using the Built-In Components</title> |
| |
| <para> |
| This section will provide examples on a couple of basis non-visual built in components, |
| that are very, very useful. The &Foreach; component (as you might have guessed from its name) |
| is used to iterator over a number of element. The other components are used to respond to |
| various user events, whether via a link or through a form button. |
| </para> |
| |
| <section id="builtin-foreach"> |
| <title>Foreach</title> |
| <para>The &Foreach; component can be used to iterate over some collection of items. |
| The supplied collection can be either a <varname>java.util.Collection</varname>, <varname>java.lang.Iterator</varname>, |
| an array of Objects, or a even a single Object (which is treated as a singleton collection). The source parameter |
| may even be null, in which case the Foreach's body is never renderred.</para> |
| |
| <para>For each element in the collection, &Foreach; will render whatever is enclosed in the element body. |
| For example, let us assume the following Java code exists on the page:</para> |
| |
| <figure> |
| <title>Foreach Example Code</title> |
| <programlisting> |
| public Collection getPeople() { |
| ... code here ... |
| } |
| </programlisting> |
| </figure> |
| |
| <para>This code would return zero or more instances of Person, defined to be:</para> |
| <figure> |
| <title>Interface Declaration, for Person</title> |
| <programlisting> |
| interface Person { |
| String getFirstName(); |
| String getLastName(); |
| int getHeight(); |
| } |
| </programlisting> |
| </figure> |
| |
| <para>We would use the following HTML Template, to show all people in a table:</para> |
| <figure> |
| <title>Example Template, for Person objects</title> |
| <programlisting> |
| <table> |
| <span jwcid="people"> |
| <tr><td><span jwcid="name"/></td></tr> |
| <tr><td><span jwcid="lastname"/></td></tr> |
| <tr><td><span jwcid="height"/> cm</td></tr> |
| </span> |
| </table> |
| </programlisting> |
| </figure> |
| |
| <para>Notice that the <varname>people</varname> element wraps the other elements. |
| With the &Foreach; component, it is valid (and required if you want to do anything useful :-) |
| to have content inside the element. The page specification will include the following:</para> |
| <figure> |
| <title>Component Definition for people iterator</title> |
| <programlisting> |
| <component id="people" type="Foreach"> |
| <binding name="source" expression="getPeople()"/> |
| </component> |
| |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="components.people.value.name"/> |
| </component> |
| |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="components.people.value.lastname"/> |
| </component> |
| |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="components.people.value.height"/> |
| </component> |
| </programlisting> |
| </figure> |
| |
| <para>This definition binds our iterator in the HTML template, |
| such that it uses the vale of <varname>getPeople()</varname> in the page class as the source of the collection. |
| In order to show the values, we use standard &InsertText; components - since for this example we just want to display the information. |
| </para> |
| |
| <para>Note the expression being used here, which is rougly equivalent to the following Java code:</para> |
| <figure> |
| <title>Foreach Java Code (or thereabouts)</title> |
| <programlisting> |
| Map components = getComponents(); |
| Foreach fe = (Foreach)components.get("people"); |
| Person person = (Person)fe.getValue(); |
| </programlisting> |
| </figure> |
| |
| <para>What is happening, is that for every object in the source collection, |
| the &Foreach; component is making it available via it's <varname>getValue()</varname> method. |
| We can use this to our advantage in the component specification, and reference it directly - as shown above.</para> |
| |
| <para>This strategy will work for simple cases where all you need to do is access |
| properties of the individual components during the iteration. |
| If you require more than this, you can request that the Foreach component 'set' the current value on some other |
| object, for every object in the source collection. To do this, specify an expression for the value property:</para> |
| <figure> |
| <title>Example 'value' property for a Foreach component spec</title> |
| <programlisting> |
| <binding name="value" expression="currentPerson"/%gt; |
| </programlisting> |
| </figure> |
| |
| <para>Here, it is expected that there is the following Java code on the page object:</para> |
| <figure> |
| <title>Java code, called by Foreach component</title> |
| <programlisting> |
| public void setCurrentPerson(Person value) { |
| // ... Store variable, or some other processing... |
| } |
| </programlisting> |
| </figure> |
| |
| <para>The Foreach component will call this method for every element that it iterates over in the source collection. |
| Of course, this approach would typically assume that the <varname>name</varname>, <varname>lastname</varname> |
| and <varname>height</varname> values were bound a little differently. |
| For example, if the collection contained only entity identifiers, then the <varname>setCurrentPerson()</varname> |
| method would use these to lookup the real data from a database or other persistent store. |
| This information would then be made available via a method such as:</para> |
| |
| <figure> |
| <title>Java code, called by Foreach component to get the value</title> |
| <programlisting> |
| public Person getPerson() { |
| // make result of the setCurrentPerson() call available here |
| } |
| </programlisting> |
| </figure> |
| <para>The component specification expressions would then read:</para> |
| <figure> |
| <title>Modified component specifications</title> |
| <programlisting> |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="person.name"/> |
| </component> |
| |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="person.lastname"/> |
| </component> |
| |
| <component id="name" type="InsertText"> |
| <binding name="value" expression="person.height"/> |
| </component> |
| </programlisting> |
| </figure> |
| |
| <para>The expressions here would retrieve the name (or other relevant attribute) of the Person in question |
| from the <emphasis role="bold">Pages</emphasis> copy of the Person instance.</para> |
| </section> |
| |
| <section id="builtin-events"> |
| <title>Handling Events</title> |
| <para>There are two primary ways by which you can handle user events in Tapestry, the Submit component and Link components. |
| The primary difference from a user point of view is the way in which they appear. |
| Submit components appears a HTML submit buttons and Link components appear as simple HTML links. |
| Submit components were covered in <xref linkend="forms"/> and so will not be covered in further detail in this tutorial. |
| Please see the &Submit; documentation if you require more information.</para> |
| |
| <para>Link components come in a variety of forms:</para> |
| <itemizedlist> |
| <listitem>GenericLink</listitem> |
| <listitem>PageLink</listitem> |
| <listitem>ActionLink</listitem> |
| <listitem>DirectLink</listitem> |
| </itemizedlist> |
| |
| <para>&GenericLink; is used to construct a simple link to some resource. |
| The resource is not Tapestry specific (i.e: the link can point to anything). GenericLink will render |
| it's body, and so an HTML template along these lines:</para> |
| |
| <figure> |
| <title>Example specification for GenericLink</title> |
| <programlisting> |
| <h1>A simple Generic Link</h1> |
| Click <span jwcid="google">here</span> to perform a search at Google. |
| </programlisting> |
| </figure> |
| <para>would produce the following when rendered:</para> |
| |
| <figure> |
| <title>Example GenericLink usage</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/events-genericlink.gif" format="GIF"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| <para>The other types of link mentioned here are Tapestry specific - that is, their parameters name |
| Tapestry resources, which are then coverted into the correct URL by Tapestry itself. |
| The &PageLink; component was used in the very first example, <xref linkend="getting-started"/> and |
| so no example code or output is provided here. If you examine the URLs generated by that |
| example, note that a correct Tapestry URL has been onstructed for you which also includes any |
| container specific context information as well. |
| </para> |
| |
| <para>The last types of links introduced here are &ActionLink; and &DirectLink;. These components are |
| very similar in that they both provide the ability for a user's action to be directed to a method on |
| some object (via a listener). The main difference between the two is that one uses the Direct service, |
| and the other the Action service. Before going further, a quick explanation is in order:<footnote><para>For |
| more detailed information, please see the Developer Reference</para></footnote></para> |
| |
| <para>Both Action and Direct services are used to handle triggering of events, as mentioned previously. |
| The Direct service will invoke the listener <emphasis>just prior</emphasis> to rendering whereas the Action service will invoke the |
| listener <emphasis>during</emphasis> rendering. </para> |
| |
| <para>To clarify (because it took the author a reasonable amount of time to appreciate the difference between the two services), |
| the action service will call the listener during the rendering phase. As a result, the page will be in the exact state it was, when the |
| ActionLink was rendered. The Direct service is much simpler, the listener is called before any page rendering takes place. So, why |
| is this important?</para> |
| |
| <para><emphasis role="bold">If your listener relies component and object state that changes during the render cycle, |
| you must use the action service</emphasis></para> |
| |
| <para>Lets look at how these components are used. Both provide the same properties such as <varname>listener</varname>, |
| and <varname>disabled</varname>. DirectLink provides an additional property called <varname>parameters</varname> |
| which is used to set parameter values in the request, for use in the handler. Apart from this, their usage within |
| the component specification is identical.</para> |
| |
| <para>To demonstrate, we will create two links, using both the action and direct services. The direct service link will |
| pass in a parameter to the listener method. In these simple examples, there will not be sufficient complexity |
| to examine the differences between the two services.<footnote><para>if you find yourself getting StaleLinkExceptions |
| using DirectLink (or a form component setup in "direct" mode) you should examine your page dependencies, |
| and if any processing is dependent upon page state then change to using the action service</para></footnote></para> |
| |
| <para>For this example, we must set the <varname>stateful</varname> to false, since we will not |
| be using a visit object and creating any kind of session. Here is the HTML, component specification |
| and java code for this example:</para> |
| |
| <figure> |
| <title>Direct/ActionLink example HTML Template</title> |
| <programlisting> |
| <h1>A simple Generic Link</h1> |
| Click <span jwcid="google">here</span> to perform a search at Google. |
| |
| <h1>ActionLink and DirectLink</h1> |
| <p> |
| This <span jwcid="direct">direct link</span> will get the time of day, |
| save it in a variable of the page, and show it underneath this paragraph |
| using a InsertText component. |
| </p> |
| |
| <p> |
| This <span jwcid="action">action link</span> will do the same thing |
| as the direct link (it uses the same listener method). If you would like |
| to observe the difference in processing, run this example from a console |
| prompt with debug enabled. The listener method will output the string |
| <pre>"TIME LISTENER METHOD CALLED"</pre>. You will notice |
| the place in the render cycle in which the method is called is different |
| depending upon the link type that you click. |
| </p> |
| |
| <p> |
| <center> |
| <span jwcid="timeofday">Time of day (or nothing) will go here</span> |
| </center> |
| |
| </body> |
| </html> |
| </programlisting> |
| </figure> |
| |
| <figure> |
| <title>Direct/ActionLink component specification</title> |
| <programlisting> |
| <page-specification class="tutorial.events.Home"> |
| |
| <component id="google" type="GenericLink"> |
| <static-binding name="href">http://www.google.com</static-binding> |
| </component> |
| |
| <component id="direct" type="DirectLink"> |
| <binding name="listener" expression="listeners.timeListener"/> |
| <binding name="stateful" expression="false"/> |
| </component> |
| |
| <component id="action" type="ActionLink"> |
| <binding name="listener" expression="listeners.timeListener"/> |
| <binding name="stateful" expression="false"/> |
| </component> |
| |
| <component id="timeofday" type="InsertText"> |
| <binding name="value" expression="pageTime"/> |
| </component> |
| </page-specification> |
| </programlisting> |
| </figure> |
| |
| <figure> |
| <title>Direct/ActionLink Java code</title> |
| <programlisting> |
| /** |
| * Example code for the event handling section of the tutorial |
| * @author neil clayton |
| */ |
| public class Home extends BasePage { |
| /** |
| * Called by both the "direct" and "action" components |
| */ |
| public void timeListener(IRequestCycle cycle) throws RequestCycleException { |
| System.err.println("TIME LISTENER METHOD CALLED"); |
| pageTime = DateFormat.getDateTimeInstance().format(new Date()); |
| } |
| |
| public String getPageTime() { |
| return pageTime; |
| } |
| |
| /** |
| * @see net.sf.tapestry.AbstractPage#detach() |
| */ |
| public void detach() { |
| pageTime = null; |
| } |
| |
| private String pageTime; |
| } |
| </programlisting> |
| </figure> |
| |
| <para>The output with debug enabled when using both the direct and action services is shown below. |
| As you can see, the direct link service is calling the method well before anything happens with the |
| components on the page. The action service on the other hand is calling the method <emphasis>just |
| before</emphasis> it renders the &InsertText; component - which is midway through it's render cycle.</para> |
| <figure> |
| <title>Example debug ouput for DirectLink call</title> |
| <programlisting> |
| ... |
| [java] AbstractDocumentParser [DEBUG] Resolved -//Howard Lewis Ship//Tapestry Specification 1.3//EN as org.xml.sax.InputSource@7a5a19 (for Tapestry_1_3.dtd) |
| [java] TIME LISTENER METHOD CALLED |
| [java] DefaultSpecificationSource [DEBUG] Parsing library specification /net/sf/tapestry/Framework.library |
| ... |
| </programlisting> |
| </figure> |
| |
| <figure> |
| <title>Example debug ouput for ActionLink call</title> |
| <programlisting> |
| ... |
| [java] AbstractDocumentParser [DEBUG] Resolved -//Howard Lewis Ship//Tapestry Specification 1.3//EN as org.xml.sax.InputSource@59a34 (for Tapestry_1_3.dtd) |
| [java] TIME LISTENER METHOD CALLED |
| [java] DefaultSpecificationSource [DEBUG] Parsing component specification /net/sf/tapestry/html/InsertText.jwc |
| ... |
| </programlisting> |
| </figure> |
| |
| <para> |
| Finally, it is worth mentioning that these other Tapestry specific link types allow parameters such as |
| <varname>disabled</varname>, |
| <varname>scheme</varname>, <varname>port</varname> and <varname>anchor</varname>. |
| Please see either the Component Reference, Developer Reference or JavaDoc API for further |
| information on these parameters</para> |
| </section> |
| </chapter> |
| |