You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by bu...@apache.org on 2015/07/19 23:21:30 UTC

svn commit: r958985 [28/29] - in /websites/production/tapestry/content: ./ 2009/09/13/ 2009/10/27/ 2009/11/25/ 2010/07/18/ 2010/07/24/ 2010/10/11/ 2010/10/31/ 2010/11/18/ 2010/12/16/ 2010/12/17/ 2011/01/18/ 2011/03/23/ 2011/03/29/ 2011/03/30/ 2011/03/3...

Modified: websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
==============================================================================
--- websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html (original)
+++ websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html Sun Jul 19 21:21:27 2015
@@ -27,6 +27,16 @@
   </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css">
 
+    <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+  <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+  <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+  <script type="text/javascript">
+  SyntaxHighlighter.defaults['toolbar'] = false;
+  SyntaxHighlighter.all();
+  </script>
 
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -57,16 +67,8 @@
   </div>
 
 <div id="content">
-<div id="ConfluenceContent"><style type="text/css">/*<![CDATA[*/
-table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
-table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
-table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
-table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
-table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
-table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
-
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="implementing-the-hi-lo-guessing-game.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="implementing-the-hi-lo-guessing-game.html">Implementing the Hi-Lo Guessing Game</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="tapestry-tutorial.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="tapestry-tutorial.html">Tapestry Tutorial</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="using-tapestry-with-hibernate.html">Using Tapestry With Hibernate</a></td><td colspan=
 "1" rowspan="1" class="ScrollbarNextIcon"><a shape="rect" href="using-tapestry-with-hibernate.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><p>In the previous chapters, we saw how Tapestry can handle simple links, even links that pass information in the URL. In this chapter, we'll see how Tapestry can do the same, and quite a bit more, for HTML forms.</p><p>Form support in Tapestry is deep and rich, more than can be covered in a single chapter. However, we can show the basics, including some very common development patterns. To get started, let's create a simple address book application.</p><p>We'll start with the entity data, a simple object to store the information we'll need. These classes go in an <code>entities</code> sub-package. Unlike the use of the <code>pages</code> sub-package (for page component classes), this is not enforced by Tapestry; it's just a convention (
 but as we'll see shortly, a handy one).</p><p>Tapestry treats public fields as if they were JavaBeans properties; since the Address object is just "dumb data", there's no need to get carried away writing getters and setters. Instead, we'll define an entity that is all public fields:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/java/com/example/tutorial/entities/Address.java</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[package com.example.tutorial.entities;
+<div id="ConfluenceContent"><p>In the previous chapters, we saw how Tapestry can handle simple links, even links that pass information in the URL. In this chapter, we'll see how Tapestry can do the same, and quite a bit more, for HTML forms.</p><p>Form support in Tapestry is deep and rich, more than can be covered in a single chapter. However, we can show the basics, including some very common development patterns. To get started, let's create a simple address book application.</p><p>We'll start with the entity data, a simple object to store the information we'll need. These classes go in an <code>entities</code> sub-package. Unlike the use of the <code>pages</code> sub-package (for page component classes), this is not enforced by Tapestry; it's just a convention (but as we'll see shortly, a handy one).</p><p>Tapestry treats public fields as if they were JavaBeans properties; since the Address object is just "dumb data", there's no need to get carried away writing getters and setter
 s. Instead, we'll define an entity that is all public fields:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/java/com/example/tutorial/entities/Address.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package com.example.tutorial.entities;
 
 import com.example.tutorial.data.Honorific;
 
@@ -83,40 +85,40 @@ public class Address
     public String email;
     public String phone;
 }
-]]></script>
+</pre>
 </div></div><p>We also need to define the enum type, Honorific:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/java/com/example/tutorial/data/Honorific.java</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[package com.example.tutorial.data;
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package com.example.tutorial.data;
 
 public enum Honorific
 {
     MR, MRS, MISS, DR
 }
-]]></script>
+</pre>
 </div></div><h1 id="UsingBeanEditFormToCreateUserForms-AddressPages">Address Pages</h1><p>We're probably going to create a few pages related to addresses: pages for creating them, for editing them, for searching and listing them. We'll create a sub-folder, address, to hold them. Let's get started on the first of these pages, "address/Create" (that's the real name, including the slash &#8212; we'll see in a minute how that maps to classes and templates).</p><p>First, we'll update the Index.tml template, to create a link to the new page:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/Index.tml (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;h1&gt;Address Book&lt;/h1&gt;
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">    &lt;h1&gt;Address Book&lt;/h1&gt;
 
     &lt;ul&gt;
-        &lt;li&gt;&lt;t:pagelink page=&quot;address/create&quot;&gt;Create new address&lt;/t:pagelink&gt;&lt;/li&gt;
+        &lt;li&gt;&lt;t:pagelink page="address/create"&gt;Create new address&lt;/t:pagelink&gt;&lt;/li&gt;
     &lt;/ul&gt;
-]]></script>
+</pre>
 </div></div><p>Now we need the address/Create page; lets start with an empty shell, just to test our navigation.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.tml</b></div><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;html t:type=&quot;layout&quot; title=&quot;Create New Address&quot;
-    xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_3.xsd&quot;&gt;
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;html t:type="layout" title="Create New Address"
+    xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"&gt;
 
     &lt;em&gt;coming soon ...&lt;/em&gt;
 
 &lt;/html&gt;
-]]></script>
+</pre>
 </div></div><p>(Note: for Tapestry 5.4, make that <code>tapestry_5_4.xsd</code> instead.)</p><p>Next, the corresponding class:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>src/main/java/com/example/tutorial/pages/address/CreateAddress.java</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[package com.example.tutorial.pages.address;
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package com.example.tutorial.pages.address;
 
 public class CreateAddress
 {
 
 }
-]]></script>
+</pre>
 </div></div><p>So ... why is the class named "CreateAddress" and not simply "Create"? Actually, we could have named it "Create", and the application would still work, but the longer <em>class</em> name is equally valid. Tapestry noticed the redundancy in the class name (com.example.tutorial.pages.<code><em>address</em></code>.Create<em>Address</em>) and just stripped out the redundant suffix.</p><p><span style="line-height: 1.4285715;">Tapestry actually creates a bunch of aliases for you pages; any of these aliases are valid and can appear in URLs or in the page parameter of PageLink. &#160;You can see the list in the console:</span></p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[[INFO] TapestryModule.ComponentClassResolver Available pages (12):
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">[INFO] TapestryModule.ComponentClassResolver Available pages (12):
               (blank): com.example.tutorial.pages.Index
    ComponentLibraries: org.apache.tapestry5.corelib.pages.ComponentLibraries
              Error404: com.example.tutorial.pages.Error404
@@ -130,71 +132,63 @@ PropertyDisplayBlocks: org.apache.tapest
         ServiceStatus: org.apache.tapestry5.corelib.pages.ServiceStatus
           T5Dashboard: org.apache.tapestry5.corelib.pages.T5Dashboard
        address/Create: com.example.tutorial.pages.address.CreateAddress
-address/CreateAddress: com.example.tutorial.pages.address.CreateAddress]]></script>
+address/CreateAddress: com.example.tutorial.pages.address.CreateAddress</pre>
 </div></div><p><span style="line-height: 1.4285715;">Tapestry users the shortest alias when constructing URLs.</span></p><p><span style="line-height: 1.4285715;">Eventually, your application will probably have more entities: perhaps you'll have a "user/Create" page and a "payment/Create" page and an "account/Create" page. You </span><em style="line-height: 1.4285715;">could</em><span style="line-height: 1.4285715;"> have a bunch of different classes all named Create spread across a number of different packages. That's legal Java, but it isn't ideal. You may find yourself accidentally editing the Java code for creating an Account when you really want to be editing the code for creating a Payment.</span></p><p>Tapestry is encouraging you to use a more descriptive name: Create<em>Address</em>, not just Create, but it isn't making you pay the cost (in terms of longer, uglier URLs). The URL to access the page will still be <a shape="rect" class="external-link" href="http://localhost:8080
 /tutorial1/address/create" >http://localhost:8080/tutorial1/address/create</a>.</p><p>And remember, regardless of the name that Tapestry assigns to your page, the template file is named like the Java class itself: CreateAddress.tml.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Index pages work in folders as well. A class named com.example.tutorial.pages.address.AddressIndex would be given the name "address/Index". However, Tapestry has special rules for pages named "Index" and the rendered URL would be <a shape="rect" class="external-link" href="http://localhost:8080/tutorial1/address/" >http://localhost:8080/tutorial1/address/</a>. In other words, you can place Index pages in any folder and Tapestry will build a short URL for that page ... and you <em>don't</em> have to keep naming the classes Ind
 ex (it's confusing to have many classes with the same name, even across multiple packages); instead, you can name each index page after the package that contains it. Tapestry users a smart <em>convention</em> to keep it all straight and generate short, to the point URLs.</p></div></div><h1 id="UsingBeanEditFormToCreateUserForms-UsingtheBeanEditFormComponent">Using the BeanEditForm Component</h1><p>Time to start putting together the logic for this form. Tapestry has a specific component for client-side Forms: the <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a> component, as well as components for form controls, such as <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Checkbox.html">Checkbox</a> and <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corel
 ib/components/TextField.html">TextField</a>. We'll cover those in a bit more detail later .. instead, we're again going to let Tapestry do the heavy lifting for us, via the <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/BeanEditForm.html">BeanEditForm</a> component.</p><p>Add the following to the CreateAddress template (replacing the "coming soon ..." message):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CreateAddress.tml (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform object=&quot;address&quot;/&gt;
-]]></script>
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">    &lt;t:beaneditform object="address"/&gt;
+</pre>
 </div></div><p>And match that up with a property in the CreateAddress class:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CreateAddress.java (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Property
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    @Property
     private Address address;
-]]></script>
-</div></div><p>When you refresh the page, you may see a warning like the following at the top of the page:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/hmac-warning.png" data-image-src="/confluence/download/attachments/23340431/hmac-warning.png?version=2&amp;modificationDate=1416883285000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="49184896" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="hmac-warning.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span></p><p>If you see that, it means you need to invent an HMAC passphrase for your app. Just edit your AppModule.java class (in your services package), adding a couple of lines to the contributeApplicationDefault
 s method like the following:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[        // Set the HMAC pass phrase to secure object data serialized to client
-        configuration.add(SymbolConstants.HMAC_PASSPHRASE, &quot;&quot;);]]></script>
-</div></div><p>but, instead of an empty string, insert a long, <strong>random string of characters</strong> (like a very long and complex password, at least 30 characters) that you keep private.</p><p>After you do that, stop the app and restart it, and click on the Create new address link again, and you'll see something like this:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/create-address-initial.png" data-image-src="/confluence/download/attachments/23340431/create-address-initial.png?version=2&amp;modificationDate=1416884366000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347017" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="create-address-initial.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data
 -linked-resource-container-version="44"></span></p><p>Tapestry has done quite a bit of work here. It has created a form that includes a field for each property. Further, it has seen that the honorific property is an enumerated type, and presented that as a drop-down list.</p><p>In addition, Tapestry has converted the property names ("city", "email", "firstName") to user presentable labels ("City", "Email", "First Name"). In fact, these are &lt;label&gt; elements, so clicking a label with the mouse will move the input cursor into the corresponding field.</p><p>This is an awesome start; it's a presentable interface, quite nice in fact for a few minute's work. But it's far from perfect; let's get started with some customizations.</p><h1 id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field Order</h1><p>The BeanEditForm must guess at the right order to present the fields; for public fields, they end up in alphabetical order. For standard JavaBeans properties, the Bea
 nEditForm default is in the order in which the getter methods are defined in the class (it uses line number information, if available).</p><p>A better order for these fields is the order in which they are defined in the Address class:</p><ul><li>honorific</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li>email</li><li>phone</li></ul><p>We can accomplish this by using the <code>reorder</code> parameter of the BeanEditForm component, which is a comma separated list of property (or public field) names:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CreateAddress.tml (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform object=&quot;address&quot;
-        reorder=&quot;honorific,firstName,lastName,street1,street2,city,state,zip,email,phone&quot; /&gt;
-]]></script>
-</div></div><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/create-address-reordered.png" data-image-src="/confluence/download/attachments/23340431/create-address-reordered.png?version=2&amp;modificationDate=1416884592000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="24347018" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="create-address-reordered.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span></p><h3 id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the fields. It's just a matter of creating a <em>message catalog</em> for the page.</p><p>In Tapestry, every page and
  component may have its own message catalog. This is a standard Java properties file, and it is named the same as the page or component class, with a ".properties" extension. A message catalog consists of a series of lines, each line is a message key and a message value separated with an equals sign.</p><p>All it takes is to create a message entry with a particular name: the name of the property suffixed with "-label". As elsewhere, Tapestry is forgiving of case.</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div class="preformattedContent panelContent">
+</pre>
+</div></div><p>When you refresh the page, you may see a warning like the following at the top of the page:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/hmac-warning.png"></span></p><p>If you see that, it means you need to invent an HMAC passphrase for your app. Just edit your AppModule.java class (in your services package), adding a couple of lines to the contributeApplicationDefaults method like the following:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">        // Set the HMAC pass phrase to secure object data serialized to client
+        configuration.add(SymbolConstants.HMAC_PASSPHRASE, "");</pre>
+</div></div><p>but, instead of an empty string, insert a long, <strong>random string of characters</strong> (like a very long and complex password, at least 30 characters) that you keep private.</p><p>After you do that, stop the app and restart it, and click on the Create new address link again, and you'll see something like this:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/create-address-initial.png"></span></p><p>Tapestry has done quite a bit of work here. It has created a form that includes a field for each property. Further, it has seen that the honorific property is an enumerated type, and presented that as a drop-down list.</p><p>In addition, Tapestry has converted the property names ("city", "email", "firstName") to user presentable labels ("City", "Email", "First Name"). In fact, these are &lt;label&gt; elements, so clicking a label with the mouse will move the input cursor into
  the corresponding field.</p><p>This is an awesome start; it's a presentable interface, quite nice in fact for a few minute's work. But it's far from perfect; let's get started with some customizations.</p><h1 id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field Order</h1><p>The BeanEditForm must guess at the right order to present the fields; for public fields, they end up in alphabetical order. For standard JavaBeans properties, the BeanEditForm default is in the order in which the getter methods are defined in the class (it uses line number information, if available).</p><p>A better order for these fields is the order in which they are defined in the Address class:</p><ul><li>honorific</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li>email</li><li>phone</li></ul><p>We can accomplish this by using the <code>reorder</code> parameter of the BeanEditForm component, which is a comma separated list of
  property (or public field) names:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CreateAddress.tml (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">    &lt;t:beaneditform object="address"
+        reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone" /&gt;
+</pre>
+</div></div><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="using-beaneditform-to-create-user-forms.data/create-address-reordered.png"></span></p><h3 id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the fields. It's just a matter of creating a <em>message catalog</em> for the page.</p><p>In Tapestry, every page and component may have its own message catalog. This is a standard Java properties file, and it is named the same as the page or component class, with a ".properties" extension. A message catalog consists of a series of lines, each line is a message key and a message value separated with an equals sign.</p><p>All it takes is to create a message entry with a particular name: the name of the property suffixed with "-label". As elsewhere, Tapestry is forgiving of case.</p><div class="preformatted panel" style="border-width: 1px;"><div cla
 ss="preformattedHeader panelHeader" style="border-bottom-width: 1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div class="preformattedContent panelContent">
 <pre>street1-label=Street 1
 street2-label=Street 2
 email-label=E-Mail
 zip-label=Zip Code
 phone-label=Phone Number</pre>
-</div></div><p>Since this is a <em>new</em> file (and not a change to an existing file), you may have to restart Jetty to force Tapestry to pick up the change.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v3.png" data-image-src="/confluence/download/attachments/23340431/address-v3.png?version=2&amp;modificationDate=1417055915000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527737" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="address-v3.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span></p><p>We can also customize the options in the drop down list. All we have to do is add some more entries to the message catalog 
 matching the enum names to the desired labels. Update CreateAddress.properties and add:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+</div></div><p>Since this is a <em>new</em> file (and not a change to an existing file), you may have to restart Jetty to force Tapestry to pick up the change.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v3.png"></span></p><p>We can also customize the options in the drop down list. All we have to do is add some more entries to the message catalog matching the enum names to the desired labels. Update CreateAddress.properties and add:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>MR=Mr.
 MRS=Mrs.
 DR=Dr.
 </pre>
 </div></div><p>Notice that we don't have to include an option for MISS, because that is converted to "Miss" anyway. You might just want to include it for sake of consistency ... the point is, each option label is searched for separately.</p><p>Lastly, the default label on the submit button is "Create/Update" (BeanEditForm doesn't know how it is being used). Let's change that to "Create Address".</p><p>That button is a component within the BeanEditForm component. It's not a property, so we can't just put a message into the message catalog, the way we can with the fields. Fortunately, the BeanEditForm component includes a parameter expressly for re-labeling the button. Simply change the CreateAddress component template:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform submitlabel=&quot;Create Address&quot; object=&quot;address&quot;
-        reorder=&quot;honorific,firstName,lastName,street1,street2,city,state,zip,email,phone&quot;/&gt;
-]]></script>
-</div></div><p>The default for the submitlabel parameter is "Create/Update", but here we're overriding that default to a specific value.</p><p>The final result shows the reformatting and relabelling:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v5.png" data-image-src="/confluence/download/attachments/23340431/address-v5.png?version=2&amp;modificationDate=1417055915000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527738" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="address-v5.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span><br clear="none">Before continuing on to validation, a side note about message catalogs. M
 essage catalogs are not just for re-labeling fields and options; we'll see in later chapters how message catalogs are used in the context of localization and internationalization.</p><p>Instead of putting the label for the submit button directly inside the template, we're going to provide a reference to the label; the actual label will go in the message catalog.</p><p>In Tapestry, when binding a parameter, the value you provide may include a prefix. The prefix guides Tapestry in how to interpret the rest of the the parameter value ... is it the name of a property? The id of a component? A message key? Most parameters have a default prefix, usually "prop:", that is used when you fail to provide one (this helps to make the templates as terse as possible).</p><p>Here we want to reference a message from the catalog, so we use the "message:" prefix:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform object=&quot;address&quot; submitlabel=&quot;message:submit-label&quot;
-        reorder=&quot;honorific,firstName,lastName,street1,street2,city,state,zip,email,phone&quot; /&gt;
-]]></script>
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">    &lt;t:beaneditform submitlabel="Create Address" object="address"
+        reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"/&gt;
+</pre>
+</div></div><p>The default for the submitlabel parameter is "Create/Update", but here we're overriding that default to a specific value.</p><p>The final result shows the reformatting and relabelling:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v5.png"></span><br clear="none">Before continuing on to validation, a side note about message catalogs. Message catalogs are not just for re-labeling fields and options; we'll see in later chapters how message catalogs are used in the context of localization and internationalization.</p><p>Instead of putting the label for the submit button directly inside the template, we're going to provide a reference to the label; the actual label will go in the message catalog.</p><p>In Tapestry, when binding a parameter, the value you provide may include a prefix. The prefix guides Tapestry in how to interpret the rest 
 of the the parameter value ... is it the name of a property? The id of a component? A message key? Most parameters have a default prefix, usually "prop:", that is used when you fail to provide one (this helps to make the templates as terse as possible).</p><p>Here we want to reference a message from the catalog, so we use the "message:" prefix:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">    &lt;t:beaneditform object="address" submitlabel="message:submit-label"
+        reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone" /&gt;
+</pre>
 </div></div><p>And then we define the submit-label key in the message catalog:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>submit-label=Create Address
 </pre>
 </div></div><p>In the end, the exact same HTML is sent to the client, regardless of whether you include the label text directly in the template, or indirectly in the message catalog. In the long term, the latter approach will work better if you later chose to internationalize your application.</p><h3 id="UsingBeanEditFormToCreateUserForms-AddingValidation">Adding Validation</h3><p>Before we worry about storing the Address object, we should make sure that the user provides reasonable values. For example, several of the fields should be required, and phone numbers and email address have specific formats.</p><p>The BeanEditForm checks for a Tapestry-specific annotation, @<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/beaneditor/Validate.html">Validate</a>, on the field, the getter method, or the setter method of each property.</p><p>Edit the Address entity, and update the lastName, firstName, street1, city, state and zip fiel
 ds, adding a @Validate annotation to each:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Validate(&quot;required&quot;)
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    @Validate("required")
     public String firstName;
-]]></script>
-</div></div><p>What is that string, "required"? That's how you specify the desired validation. It is a series of names that identify what type of validation is desired. A number of validators are built in, such as "required", "minLength" and "maxLength". As elsewhere, Tapestry is case insensitive.</p><p>You can apply multiple validations, by separating the validator names with commas. Some validators can be configured (with an equals sign). Thus you might say "required,minLength=5" for a field that must be specified, and must be at least five characters long.</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>You can easily get confused when you make a change to an entity class, such as adding the @Validate annotation, and <em>not</em> see the result in the browser. Only component classes, and (most) classe
 s in the Tapestry services layer, are live-reloaded. Data and entity objects are not reloaded, so this is one area where you need to stop and restart Jetty to see the change.</p></div></div><p>Restart the application, and refresh your browser, then hit the Create Address button.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v6.png" data-image-src="/confluence/download/attachments/23340431/address-v6.png?version=3&amp;modificationDate=1417056607000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527739" data-linked-resource-version="3" data-linked-resource-type="attachment" data-linked-resource-default-alias="address-v6.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span></p><p>Thi
 s is a shot just after hitting the Create Address button; all the fields have been validated and errors displayed. Each field in error has been highlighted in red and had an error message added. Further, the label for each of the fields has also been highlighted in red, to even more clearly identify what's in error. The cursor has also been moved to the first field that's in error. And <em>all</em> of this is taking place on the client side, without any communication with the application.</p><p>Once all the errors are corrected, and the form does submit, all validations are performed on the server side as well (just in case the client has JavaScript disabled).</p><p>So ... how about some more interesting validation than just "required or not". Tapestry has built in support for validating based on field length and several variations of field value, including regular expressions. Zip codes are pretty easy to express as a regular expression.</p><div class="code panel pdl" style="border
 -width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Validate(&quot;required,regexp=^\\d{5}(-\\d{4})?$&quot;)
+</pre>
+</div></div><p>What is that string, "required"? That's how you specify the desired validation. It is a series of names that identify what type of validation is desired. A number of validators are built in, such as "required", "minLength" and "maxLength". As elsewhere, Tapestry is case insensitive.</p><p>You can apply multiple validations, by separating the validator names with commas. Some validators can be configured (with an equals sign). Thus you might say "required,minLength=5" for a field that must be specified, and must be at least five characters long.</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>You can easily get confused when you make a change to an entity class, such as adding the @Validate annotation, and <em>not</em> see the result in the browser. Only component classes, and (most) classe
 s in the Tapestry services layer, are live-reloaded. Data and entity objects are not reloaded, so this is one area where you need to stop and restart Jetty to see the change.</p></div></div><p>Restart the application, and refresh your browser, then hit the Create Address button.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v6.png"></span></p><p>This is a shot just after hitting the Create Address button; all the fields have been validated and errors displayed. Each field in error has been highlighted in red and had an error message added. Further, the label for each of the fields has also been highlighted in red, to even more clearly identify what's in error. The cursor has also been moved to the first field that's in error. And <em>all</em> of this is taking place on the client side, without any communication with the application.</p><p>Once all t
 he errors are corrected, and the form does submit, all validations are performed on the server side as well (just in case the client has JavaScript disabled).</p><p>So ... how about some more interesting validation than just "required or not". Tapestry has built in support for validating based on field length and several variations of field value, including regular expressions. Zip codes are pretty easy to express as a regular expression.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    @Validate("required,regexp=^\\d{5}(-\\d{4})?$")
     public String zip;
-]]></script>
-</div></div><p>Let's give it a try; restart the application and enter an "abc" for the zip code.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v7.png" data-image-src="/confluence/download/attachments/23340431/address-v7.png?version=2&amp;modificationDate=1417056608000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527740" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="address-v7.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span><br clear="none">This is what you'll see after typing "abc" and clicking the Create Address button.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="a
 ui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Modern browsers will automatically validate a regexp field when the form is submitted, as shown above. Older browsers do not have that automatic support, but will still validate input, using the same decorations as for the required fields in the previous screenshot.</p></div></div><p>In any case, that's the right validation behavior, but it's the wrong message. Your users are not going to know or care about regular expressions.</p><p>Fortunately, it's easy to customize validation messages. All we need to know is the name of the property ("zip") and the name of the validator ("regexp"). We can then put an entry into the CreateAddress message catalog:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+</pre>
+</div></div><p>Let's give it a try; restart the application and enter an "abc" for the zip code.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v7.png"></span><br clear="none">This is what you'll see after typing "abc" and clicking the Create Address button.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Modern browsers will automatically validate a regexp field when the form is submitted, as shown above. Older browsers do not have that automatic support, but will still validate input, using the same decorations as for the required fields in the previous screenshot.</p></div></div><p>In any case, that's the right validation behavior, but it's the wrong message. Your users
  are not going to know or care about regular expressions.</p><p>Fortunately, it's easy to customize validation messages. All we need to know is the name of the property ("zip") and the name of the validator ("regexp"). We can then put an entry into the CreateAddress message catalog:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 90125-1655.
 </pre>
-</div></div><p>Refresh the page and submit again:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v8.png" data-image-src="/confluence/download/attachments/23340431/address-v8.png?version=2&amp;modificationDate=1417056608000&amp;api=v2" data-unresolved-comment-count="0" data-linked-resource-id="23527741" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="address-v8.png" data-base-url="https://cwiki.apache.org/confluence" data-linked-resource-content-type="image/png" data-linked-resource-container-id="23340431" data-linked-resource-container-version="44"></span></p><p>This trick isn't limited to just the regexp validator, it works equally well with <em>any</em> validator.</p><p>Let's go one step further. Turns out, we can move the regexp pattern to the message catalog as well. If you only provide 
 the name of the validator in the @Validate annotation, Tapestry will search the containing page's message catalog of the constraint value, as well as the validation message. The constraint value for the regexp validator is the regular expression to match against.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    @Validate(&quot;required,regexp&quot;)
+</div></div><p>Refresh the page and submit again:</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="using-beaneditform-to-create-user-forms.data/address-v8.png"></span></p><p>This trick isn't limited to just the regexp validator, it works equally well with <em>any</em> validator.</p><p>Let's go one step further. Turns out, we can move the regexp pattern to the message catalog as well. If you only provide the name of the validator in the @Validate annotation, Tapestry will search the containing page's message catalog of the constraint value, as well as the validation message. The constraint value for the regexp validator is the regular expression to match against.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    @Validate("required,regexp")
     public String zip;
-]]></script>
+</pre>
 </div></div><p>Now, just put the regular expression into the CreateAddress message catalog:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>zip-regexp=^\\d{5}(-\\d{4})?$
 zip-regexp-message=Zip Codes are five or nine digits.  Example: 02134 or 90125-1655.
 </pre>
-</div></div><p>After a restart you'll see the ... the same behavior. But when we start creating more complicated regular expressions, it'll be much, much nicer to put them in the message catalog rather than inside the annotation value. And inside the message catalog, you can change and tweak the regular expressions without having to restart the application each time.</p><p>We could go a bit further here, adding more regular expression validation for phone numbers and e-mail addresses. We're also far from done in terms of further customizations of the BeanEditForm component.</p><p>By now you are likely curious about what happens <em>after</em> the form submits successfully (without validation errors), so that's what we'll focus on next.</p><hr><p>&#160;</p><style type="text/css">/*<![CDATA[*/
-table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
-table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
-table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
-table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
-table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
-table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
-
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="implementing-the-hi-lo-guessing-game.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="implementing-the-hi-lo-guessing-game.html">Implementing the Hi-Lo Guessing Game</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="tapestry-tutorial.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="tapestry-tutorial.html">Tapestry Tutorial</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="using-tapestry-with-hibernate.html">Using Tapestry With Hibernate</a></td><td colspan=
 "1" rowspan="1" class="ScrollbarNextIcon"><a shape="rect" href="using-tapestry-with-hibernate.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div></div>
+</div></div><p>After a restart you'll see the ... the same behavior. But when we start creating more complicated regular expressions, it'll be much, much nicer to put them in the message catalog rather than inside the annotation value. And inside the message catalog, you can change and tweak the regular expressions without having to restart the application each time.</p><p>We could go a bit further here, adding more regular expression validation for phone numbers and e-mail addresses. We're also far from done in terms of further customizations of the BeanEditForm component.</p><p>By now you are likely curious about what happens <em>after</em> the form submits successfully (without validation errors), so that's what we'll focus on next.</p><hr><p>&#160;</p></div>
 </div>
 
 <div class="clearer"></div>

Modified: websites/production/tapestry/content/using-jsr-330-standard-annotations.html
==============================================================================
--- websites/production/tapestry/content/using-jsr-330-standard-annotations.html (original)
+++ websites/production/tapestry/content/using-jsr-330-standard-annotations.html Sun Jul 19 21:21:27 2015
@@ -27,6 +27,16 @@
   </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css">
 
+    <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+  <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+  <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+  <script type="text/javascript">
+  SyntaxHighlighter.defaults['toolbar'] = false;
+  SyntaxHighlighter.all();
+  </script>
 
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -57,15 +67,7 @@
   </div>
 
 <div id="content">
-<div id="ConfluenceContent"><style type="text/css">/*<![CDATA[*/
-table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
-table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
-table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
-table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
-table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
-table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
-
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="logging-in-tapestry.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="logging-in-tapestry.html">Logging in Tapestry</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="ioc.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="ioc.html">IoC</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="operation-tracker.html">Operation Tracker</a></td><td colspan="1" rowspan="1" class="ScrollbarNextIcon"><a shape="rect" href="operation-tracker.html"><img align="middle" border="0
 " src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div>
+<div id="ConfluenceContent">
 
 
 
@@ -91,17 +93,17 @@ org.apache.tapestry5.ioc.annotations </p
 
 <p>Let&#8217;s start with field injection. In Tapestry the injection into fields is triggered by&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">@Inject</a>&#160;or&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">@InjectService</a>&#160;annotations. When @Inject annotation is present on a field, Tapestry tries to resolve the object to inject by the type of the field. If several implementations of the same service interface are available in the registry, you have to disambiguate which implementation you want to be injected. This can be done by placing the&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">@InjectService</a>&#160;annotation on the injection point.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[import org.apache.tapestry5.ioc.annotations.Inject;
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.annotations.InjectService;
 
 ...
 
 public class AuthenticationFilter implements ComponentRequestFilter {
 
-   @InjectService(&quot;HttpBasic&quot;)
+   @InjectService("HttpBasic")
    private AuthenticationService basicAuthService;
 
-   @InjectService(&quot;HttpDigest&quot;)
+   @InjectService("HttpDigest")
    private AuthenticationService digestAuthService;
 
    @Inject
@@ -109,21 +111,21 @@ public class AuthenticationFilter implem
 
    ...
 
-}]]></script>
+}</pre>
 </div></div>
 <p>Now let&#8217;s see the JSR-330 equivalent of the same service. As you can see the @Inject annotations are interchangeable. The difference is how to get a service by its unique id. For this purpose JSR-330 provides the&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Named.html" >@Named</a>&#160;annotation which accompanies the @Inject annotation.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[import javax.inject.Inject;
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">import javax.inject.Inject;
 import javax.inject.Named;
 
 ...
 
 public class AuthenticationFilter implements ComponentRequestFilter {
 
-   @Inject @Named(&quot;HttpBasic&quot;)
+   @Inject @Named("HttpBasic")
    private AuthenticationService basicAuthService;
 
-   @Inject @Named(&quot;HttpDigest&quot;)
+   @Inject @Named("HttpDigest")
    private AuthenticationService digestAuthService;
 
    @Inject
@@ -131,7 +133,7 @@ public class AuthenticationFilter implem
 
    ...
 
-}]]></script>
+}</pre>
 </div></div>
 
 <h1 id="UsingJSR330standardannotations-ConstructorInjection">Constructor Injection</h1>
@@ -140,27 +142,27 @@ public class AuthenticationFilter implem
 
 <p>However, the semantics of constructor injection are different in JSR-330 and Tapestry IoC. In JSR-330 a constructor is injectable only if the @Inject annotation is present.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Car {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Car {
 
    public Car() { ... }
 
    @Inject
    public Car(Engine engine) { ... }
-}]]></script>
+}</pre>
 </div></div>
 <p>In Tapestry the @Inject annotation for constructors is optional. All available constructors are candidates for injection: the constructor with the most parameters will be invoked.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Car {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Car {
 
    public Car() { ... }
 
    public Car(Engine engine) { ... }
 
-}]]></script>
+}</pre>
 </div></div>
 <p>When several constructors are available and you don&#8217;t want the constructor with most&#160; parameters to be injectable, you need to place the&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">@Inject</a>&#160;annotation.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Car {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Car {
 
    public Car() { ... }
 
@@ -169,14 +171,14 @@ public class AuthenticationFilter implem
 
    public Car(Engine engine, Logger logger) { ... }
 
-}]]></script>
+}</pre>
 </div></div>
 
 <h1 id="UsingJSR330standardannotations-InjectionIntoPagesandComponents">Injection Into Pages and Components</h1>
 
 <p>Inside Tapestry components, injection occurs exclusively on fields. So far the injection was triggered by the&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">@Inject</a>&#160;or&#160;<a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">@InjectService</a>&#160;annotations. As of version 5.3 the injection points can also be marked with JSR-330 annotations. The following example demonstrates that.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Index {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Index {
 
    @Inject
    private Request request;
@@ -185,7 +187,7 @@ public class AuthenticationFilter implem
    private ComponentResources resources;
 
    @javax.inject.Inject
-   @Named(&quot;FrenchGreeter&quot;)
+   @Named("FrenchGreeter")
    private Greeter greeter;
 
    @javax.inject.Inject
@@ -194,7 +196,7 @@ public class AuthenticationFilter implem
 
    void onActivate() { ... }
 
-}]]></script>
+}</pre>
 </div></div>
 
 
@@ -203,22 +205,22 @@ public class AuthenticationFilter implem
 
 <p>Both JSR-330 and Tapestry IoC allow you to disambiguate services by marker or qualifier annotations, as shown in the following example.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Index {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Index {
 
    @Inject
    @French
    private Greeter greeter;
 
-}]]></script>
+}</pre>
 </div></div>
 <p>Again, there is a slight difference. In JSR-330 a qualifier annotation like&#160;<em>@French</em>&#160;in the example above needs to be annotated by the&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Qualifier.html" >@Qualifier</a>&#160;annotation.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[@Documented
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 @javax.inject.Qualifier
 public @interface French {
-}]]></script>
+}</pre>
 </div></div>
 <p>In Tapestry any annotation can be a marker annotation. You don&#8217;t need to place something like the&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Qualifier.html" >@Qualifier</a>&#160;annotation on your marker annotation.</p>
 
@@ -226,7 +228,7 @@ public @interface French {
 
 <p>Injectable methods is a next slight difference. In JSR-330 a method is injectable if the @Inject annotation is present. In Tapestry the @Inject annotation is optional. An ordinary setter method is a candidate to perform injection.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class Car {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class Car {
 
    private Engine engine;
 
@@ -234,22 +236,22 @@ public @interface French {
       this.engine = engine;
    }
 
-}]]></script>
+}</pre>
 </div></div>
 <p>When building a&#160;<em>Car</em>&#160;instance, Tapestry IoC will try to resolve a service of type&#160;<em>Engine</em>. If available, Tapestry will perform injection by invoking the setter method.</p>
 
 <p>Besides that, module methods are injectable. Again, there is no need to mark the methods with @Inject annotation as Tapestry explicitly knows which module methods to invoke. In the following example you can see how to use&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Named.html" >@Named</a>&#160;annotation to inject a service by id into a&#160;<em>contribute method</em>.</p>
 <div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class TapestryModule {
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class TapestryModule {
 
    @Contribute(BindingSource.class)
    public static void provideBindings(
          MappedConfiguration&lt;String, BindingFactory&gt; cfg,
 
-         @Named(&quot;PropBindingFactory&quot;)
+         @Named("PropBindingFactory")
          BindingFactory propBindingFactory,
 
-         @Named(&quot;MessageBindingFactory&quot;)
+         @Named("MessageBindingFactory")
          BindingFactory messageBindingFactor ) {
 
       cfg.add(BindingConstants.PROP,
@@ -260,7 +262,7 @@ public @interface French {
    }
 
    ...
-}]]></script>
+}</pre>
 </div></div>
 
 
@@ -270,16 +272,7 @@ public @interface French {
 <p>By default, a JSR-330 injector creates an instance, uses the instance for one injection, and then forgets it. By placing the&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Scope.html" >@Scope</a>&#160;annotation you can tell the injector to retain the instance for possible reuse in a later injection. If you want a service to be a singleton, you need to use the&#160;<a shape="rect" class="external-link" href="http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/Singleton.html" >@Singleton</a>&#160;annotation.</p>
 
 <p>In Tapestry, it is exactly the other way around. By default a service is a singleton. Once an instance is created, it is reused for injection. Another available scope is <em>perthread</em>, which exists primarily to help multi-threaded servlet applications. If a service has <em>perthread</em>&#160;scope, it is recreated for every incoming request.</p>
-
-<style type="text/css">/*<![CDATA[*/
-table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
-table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
-table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
-table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
-table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
-table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
-
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="logging-in-tapestry.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="logging-in-tapestry.html">Logging in Tapestry</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="ioc.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="ioc.html">IoC</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="operation-tracker.html">Operation Tracker</a></td><td colspan="1" rowspan="1" class="ScrollbarNextIcon"><a shape="rect" href="operation-tracker.html"><img align="middle" border="0
 " src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div></div>
+</div>
 </div>
 
 <div class="clearer"></div>

Modified: websites/production/tapestry/content/using-select-with-a-list.html
==============================================================================
--- websites/production/tapestry/content/using-select-with-a-list.html (original)
+++ websites/production/tapestry/content/using-select-with-a-list.html Sun Jul 19 21:21:27 2015
@@ -27,6 +27,16 @@
   </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css">
 
+    <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+  <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+  <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+  <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+  <script type="text/javascript">
+  SyntaxHighlighter.defaults['toolbar'] = false;
+  SyntaxHighlighter.all();
+  </script>
 
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -57,23 +67,15 @@
   </div>
 
 <div id="content">
-<div id="ConfluenceContent"><style type="text/css">/*<![CDATA[*/
-table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color: #f0f0f0}
-table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
-table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
-table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
-table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
-table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}
-
-/*]]>*/</style><div class="Scrollbar"><table class="ScrollbarTable"><tr><td colspan="1" rowspan="1" class="ScrollbarPrevIcon"><a shape="rect" href="meta-programming-page-content.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/back_16.gif" width="16" height="16"></a></td><td colspan="1" rowspan="1" class="ScrollbarPrevName" width="33%"><a shape="rect" href="meta-programming-page-content.html">Meta-Programming Page Content</a>&#160;</td><td colspan="1" rowspan="1" class="ScrollbarParent" width="33%"><sup><a shape="rect" href="cookbook.html"><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/up_16.gif" width="8" height="8"></a></sup><a shape="rect" href="cookbook.html">Cookbook</a></td><td colspan="1" rowspan="1" class="ScrollbarNextName" width="33%">&#160;<a shape="rect" href="ioc-cookbook.html">IoC cookbook</a></td><td colspan="1" rowspan="1" class="ScrollbarNextIcon"><a shape="rect" href="ioc-cookbook.html"
 ><img align="middle" border="0" src="https://cwiki.apache.org/confluence/images/icons/forwd_16.gif" width="16" height="16"></a></td></tr></table></div><h1 id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a List</h1><p>The documentation for the <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select Component</a> and the <a shape="rect" href="tutorial.html">Tapestry Tutorial</a> provide simplistic examples of populating a drop-down menu (as the (X)HTML <em>Select</em> element) using comma-delimited strings and enums. However, most real-world Tapestry applications need to populate such menus using values from a database, commonly in the form of java.util.List objects. Doing so generally requires a <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a> and a <a shape="rect" class="external-link"
  href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a> bound to the Select component with its "model" and "encoder" parameters:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;t:select t:id=&quot;colorMenu&quot; value=&quot;selectedColor&quot; model=&quot;ColorSelectModel&quot; encoder=&quot;colorEncoder&quot; /&gt;
-]]></script>
+<div id="ConfluenceContent"><h1 id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a List</h1><p>The documentation for the <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select Component</a> and the <a shape="rect" href="tutorial.html">Tapestry Tutorial</a> provide simplistic examples of populating a drop-down menu (as the (X)HTML <em>Select</em> element) using comma-delimited strings and enums. However, most real-world Tapestry applications need to populate such menus using values from a database, commonly in the form of java.util.List objects. Doing so generally requires a <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a> and a <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a> bound to the Sel
 ect component with its "model" and "encoder" parameters:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">&lt;t:select t:id="colorMenu" value="selectedColor" model="ColorSelectModel" encoder="colorEncoder" /&gt;
+</pre>
 </div></div><p>In the above example, ColorSelectModel must be of type SelectModel, or anything that Tapestry knows how to <a shape="rect" href="parameter-type-coercion.html">coerce</a> into a SelectModel, such as a List or a Map or a "value=label,value=label,..." delimited string, or anything Tapestry knows how to coerce into a List or Map, such as an Array or a comma-delimited String.</p><h2 id="UsingSelectWithaList-SelectModel">SelectModel</h2><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demos:</strong><br clear="none">
     <a shape="rect" class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject" >Total Control Object Select</a><br clear="none">
     <a shape="rect" class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id" >ID Select</a><br clear="none">
     <a shape="rect" class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid" >Easy ID Select</a></p></div><p>A SelectModel is a collection of options (specifically <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html">OptionModel</a> objects) for a drop-down menu. Basically, each option is a value (an object) and a label (presented to the user).</p><p>If you provide a property of type List for the "model" parameter, Tapestry automatically builds a SelectModel that uses each object's toString() for both the select option value and the select option label. For database-derrived lists this is rarely useful, however, since after form submission you would then have to look up the selected object using that label.</p><p>If you provide a Map, Tapestry builds a SelectModel that uses each item's key as the encoded value and its value as the user-visible label. This is more usef
 ul, but if you are going to build a copy of the list as a map just for this purpose, you may as well let Tapestry do it for you, using SelectModelFactory.</p><h2 id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have Tapestry create a SelectModel for you, use the <a shape="rect" class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html">SelectModelFactory</a> service. SelectModelFactory creates a SelectModel from a List of objects (of whatever type) and a label property name that you choose:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page class)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[@Property
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Property
 private SelectModel colorSelectModel;
 @Inject
 SelectModelFactory selectModelFactory;
@@ -83,27 +85,27 @@ void setupRender() {
     List&lt;Color&gt; colors = colorService.findAll();
 
     // create a SelectModel from my list of colors
-    colorSelectModel = selectModelFactory.create(colors, &quot;name&quot;);
+    colorSelectModel = selectModelFactory.create(colors, "name");
 }
-]]></script>
+</pre>
 </div></div><p>The resulting SelectModel has a selectable option (specifically, an OptionModel) for every object in the original List. The label property name (the "name" property, in this example) determines the user-visible text of each menu option, and your ValueEncoder's toClient() method provides the encoded value (most commonly a simple number). If you don't provide a ValueEncoder, the result of the objects' toString() method (Color#toString() in this example) is used. Although not a recommended practice, you <em>could</em> set your toString() to return the object's ID for this purpose:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Color.java (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[...
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">...
 @Override
 public String toString() {
     return String.valueOf(this.getId()); 
 }
-]]></script>
+</pre>
 </div></div><p>But that is contorting the purpose of the toString() method, and if you go to that much trouble you're already half way to the recommended practice: creating a ValueEncoder.</p><h2 id="UsingSelectWithaList-ValueEncoder">ValueEncoder</h2><p>In addition to a SelectModel, your Select menu is likely to need a ValueEncoder. While a SelectModel is concerned only with how to construct a Select menu, a ValueEncoder is used when constructing the Select menu <em>and</em> when interpreting the encoded value that is submitted back to the server. A ValueEncoder is a converter between the type of objects you want to represent as options in the menu and the client-side encoded values that uniquely identify them, and vice-versa.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong><br clear="none">
     <a shape="rect" class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyobject" >Easy Object Select</a></p></div><p>Most commonly, your ValueEncoder's toClient() method will return a unique ID (e.g. a database primary key, or perhaps a UUID) of the given object, and its toValue() method will return the <em>object</em> matching the given ID by doing a database lookup (ideally using a service or DAO method).</p><p>If you're using one of the ORM integration modules (<a shape="rect" href="hibernate.html">Tapestry-Hibernate</a>, <a shape="rect" href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a shape="rect" class="external-link" href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder" >Tapestry-Cayenne</a>), the ValueEncoder is automatically provided for each of your mapped entity classes. The Hibernate module's implementation is typical: the primary key field of the object (converted to a String) is used as the client-side va
 lue, and that same primary key is used to look up the selected object.</p><p>That's exactly what you should do in your own ValueEncoders too:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your com.example.myappname.encoders package)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[public class ColorEncoder implements ValueEncoder&lt;Color&gt;, ValueEncoderFactory&lt;Color&gt; { 
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class ColorEncoder implements ValueEncoder&lt;Color&gt;, ValueEncoderFactory&lt;Color&gt; { 
 
     @Inject
     private ColorService colorService;
 
     @Override
     public String toClient(Color value) {
-        // return the given object&#39;s ID
+        // return the given object's ID
         return String.valueOf(value.getId()); 
     }
 
@@ -119,9 +121,9 @@ public String toString() {
         return this; 
     }
 } 
-]]></script>
+</pre>
 </div></div><p>Alternatively, if you don't expect to need a particular ValueEncoder more than once in your app, you might want to just create it on demand, using an anonymous inner class, from the getter method in the component class where it is needed. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page class, partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[    . . .
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">    . . .
 
     public ValueEncoder&lt;Color&gt; getColorEncoder() {
 
@@ -129,7 +131,7 @@ public String toString() {
 
             @Override
             public String toClient(Color value) {
-                // return the given object&#39;s ID
+                // return the given object's ID
                 return String.valueOf(value.getId()); 
             }
 
@@ -140,34 +142,34 @@ public String toString() {
             }
         }; 
     }
-]]></script>
+</pre>
 </div></div><p>Notice that the body of this anonymous inner class is the same as the body of the ColorEncoder top level class, except that we don't need a <code>create</code> method.</p><h2 id="UsingSelectWithaList-ApplyingyourValueEncoderAutomatically">Applying your ValueEncoder Automatically</h2><p>If your ValueEncoder <em>implements ValueEncoderFactory</em> (as the ColorEncoder top level class does, above), you can associate your custom ValueEncoder with your entity class so that Tapestry will automatically use it every time a ValueEncoder is needed for items of that type (such as with the Select, RadioGroup, Grid, Hidden and AjaxFormLoop components). Just add lines like the following to your module class (usually AppModule.java):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[...
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">...
     public static void contributeValueEncoderSource(MappedConfiguration&lt;Class&lt;Color&gt;,
                         ValueEncoderFactory&lt;Color&gt;&gt; configuration) { 
         configuration.addInstance(Color.class, ColorEncoder.class);
     }
-]]></script>
+</pre>
 </div></div><p>If you are contributing more than one ValueEncoder, you'll have to use raw types, like this:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[...
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">...
     public static void contributeValueEncoderSource(MappedConfiguration&lt;Class,
                         ValueEncoderFactory&gt; configuration)
     {
         configuration.addInstance(Color.class, ColorEncoder.class);
         configuration.addInstance(SomeOtherType.class, SomeOtherTypeEncoder.class);
     }
-]]></script>
+</pre>
 </div></div><h2 id="UsingSelectWithaList-WhatifIomittheValueEncoder?">What if I omit the ValueEncoder?</h2><p>The Select component's "encoder" parameter is optional, but if the "value" parameter is bound to a complex object (not a simple String, Integer, etc.) and you don't provide a ValueEncoder with the "encoder" parameter (and one isn't provided automatically by, for example, the Tapestry Hibernate integration), you'll receive a "Could not find a coercion" exception (when you submit the form) as Tapestry tries to convert the selected option's encoded value back to the <em>object</em> in your Select's "value" parameter. To fix this, you'll either have to 1) provide a ValueEncoder, 2) provide a <a shape="rect" href="type-coercion.html">Coercion</a>, or 3) use a simple value (String, Integer, etc.) for your Select's "value" parameter, and then you'll have to add logic in the corresponding onSuccess event listener method:</p><div class="code panel pdl" style="border-width: 1px;"><div
  class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>SelectWithListDemo.tml (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[&lt;t:select t:id=&quot;colorMenu&quot; value=&quot;selectedColorId&quot; model=&quot;ColorSelectModel&quot; /&gt;
-]]></script>
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">&lt;t:select t:id="colorMenu" value="selectedColorId" model="ColorSelectModel" /&gt;
+</pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (partial)</b></div><div class="codeContent panelContent pdl">
-<script class="brush: java; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[...
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">...
     public void onSuccessFromMyForm() {
         // look up the color object from the ID selected
     	selectedColor = colorService.findById(selectedColorId);
     	...
     }
-]]></script>
+</pre>
 </div></div><p>But then again, you may as well create a ValueEncoder instead.</p><h2 id="UsingSelectWithaList-Whyisthissohard?">Why is this so hard?</h2><p>Actually, it's really pretty easy if you follow the examples above. But why is Tapestry designed to use SelectModels and ValueEncoders anyway? Well, in short, this design allows you to avoid storing (via @Persist, @SessionAttribute or @SessionState) the entire (potentially large) list of objects in the session or rebuilding the whole list of objects again (though only one is needed) when the form is submitted. The chief benefits are reduced memory use and <a shape="rect" href="performance-and-clustering.html">more scalable clustering</a> due to having far less HTTP session data to replicate across the nodes of a cluster.</p></div>
 </div>