Author: buildbot
Date: Tue Nov 25 03:21:11 2014
New Revision: 930385

Log:
Production update by buildbot for tapestry

Added:
    
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/hmac-warning.png
   (with props)
Modified:
    websites/production/tapestry/content/cache/main.pageCache
    
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/create-address-initial.png
    
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/create-address-reordered.png
    
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html

Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.

Modified: 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/create-address-initial.png
==============================================================================
Binary files - no diff available.

Modified: 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/create-address-reordered.png
==============================================================================
Binary files - no diff available.

Added: 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/hmac-warning.png
==============================================================================
Binary file - no diff available.

Propchange: 
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/hmac-warning.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

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
 Tue Nov 25 03:21:11 2014
@@ -48,19 +48,13 @@
 </div></div>
 
 <div id="top">
-<div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 
1em .1em 1em">
-<p>
-<span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; 
blogs:</span>
-</p><form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
+<div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 
1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, 
wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" 
action="http://tapestry.apache.org/search.html";>
   <input type="text" name="q">
   <input type="submit" value="Search">
 </form>
 
-</div>
-
-<div class="emblem" style="float:left"><a shape="rect" href="index.html"><img 
class="confluence-embedded-image" 
src="https://cwiki.apache.org/confluence/download/attachments/21791252/tapestry_s.png?version=3&amp;modificationDate=1293093635000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/21791252/tapestry_s.png?version=3&amp;modificationDate=1293093635000&amp;api=v2"></a></div>
-<div class="title" style="float:left; margin: 0 0 0 3em">
-<h1 id="SmallBanner-PageTitle">Using BeanEditForm To Create User 
Forms</h1></div></div>
+</div><div class="emblem" style="float:left"><p><a shape="rect" 
href="index.html"><img class="confluence-embedded-image 
confluence-external-resource" 
src="http://tapestry.apache.org/images/tapestry_small.png"; 
data-image-src="http://tapestry.apache.org/images/tapestry_small.png";></a></p></div><div
 class="title" style="float:left; margin: 0 0 0 3em"><h1 
id="SmallBanner-PageTitle">Using BeanEditForm To Create User 
Forms</h1></div></div>
 <div class="clearer"></div>
 </div>
 
@@ -87,16 +81,16 @@ import com.example.tutorial.data.Honorif
 
 public class Address
 {
-  public Honorific honorific;
-  public String firstName;
-  public String lastName;
-  public String street1;
-  public String street2;
-  public String city;
-  public String state;
-  public String zip;
-  public String email;
-  public String phone;
+    public Honorific honorific;
+    public String firstName;
+    public String lastName;
+    public String street1;
+    public String street2;
+    public String city;
+    public String state;
+    public String zip;
+    public String email;
+    public String phone;
 }
 ]]></script>
 </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">
@@ -104,21 +98,21 @@ public class Address
 
 public enum Honorific
 {
-  MR, MRS, MISS, DR
+    MR, MRS, MISS, DR
 }
 ]]></script>
 </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="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[    &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=&quot;address/create&quot;&gt;Create new 
address&lt;/t:pagelink&gt;&lt;/li&gt;
     &lt;/ul&gt;
 ]]></script>
 </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="theme: Default; brush: xml; gutter: false" 
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;
+    xmlns:t=&quot;http://tapestry.apache.org/schema/tapestry_5_3.xsd&quot;&gt;
 
-  &lt;em&gt;coming soon ...&lt;/em&gt;
+    &lt;em&gt;coming soon ...&lt;/em&gt;
 
 &lt;/html&gt;
 ]]></script>
@@ -137,89 +131,20 @@ public class CreateAddress
                     </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/corelib/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/coreli
 b/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="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[  &lt;t:beaneditform 
object=&quot;address&quot;/&gt;
+<script class="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform 
object=&quot;address&quot;/&gt;
 ]]></script>
 </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="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[  @Property
-  private Address address;
+<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[    @Property
+    private Address address;
 ]]></script>
-</div></div><p>When you refresh the page, you'll see the following:</p><p><img 
class="confluence-embedded-image" width="700" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=1&amp;modificationDate=1291927518000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/create-address-initial.png?version=1&amp;modificationDate=1291927518000&amp;api=v2"></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</p><p></p><p></p><p></p><p>&lt;style type='text/css'&gt;
-.FootnoteMarker, .FootnoteNum a {
-  background: transparent 
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png)
 no-repeat top right;
-  padding: 1px 2px 0px 1px;
-  border-left: 1px solid #8898B8;
-  border-bottom: 1px solid #6B7C9B;
-  margin: 1px;
-  text-decoration: none;
-}
-.FootnoteNum a {
-  margin-top: 2px;
-  margin-right: 0px;
-}
-.FootnoteNum {
-  font-size: x-small;
-  text-align: right;
-  padding-bottom: 4px;
-}
-.footnote-th1 {
-  text-align: right;
-}
-.Footnote {
-  padding-left: 7px;
-  margin-bottom: 4px;
-  border: 1px none #DDDDDD;
-  writingMode: tb-rl;
-}
-.accessibility {
-     display: none;
-     visibility: hidden;
-}
-@media aural,braille,embossed {
-        .FootnoteMarker, .FootnoteNum a {
-         border: 1px solid #000000;
-         background: #ffffff none;
-    }
-    .accessibility {
-         display: run-in;
-         visibility: visible;
-    }
-}
-&lt;/style&gt;
-&lt;script type='text/javascript' language='JavaScript'&gt;
-//&lt;!--\n
-var effectInProgress = {};
-var despamEffect = function (id,effectType,duration) {
-  if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || 
(typeof(Effect[effectType])=="undefined")) return;
-  new Effect[effectType](id);
-  effectInProgress[id]=true;
-  setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
-};
-var oldFootnoteId = '';
-var footnoteHighlight = function(id,pulsateNum) {
-  if (oldFootnoteId!='') 
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none';
-  oldFootnoteId = id;
-  document.getElementById('Footnote'+id).style['borderStyle'] = 'solid';
-  despamEffect('Footnote'+id,'Highlight',1)
-  if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
-}
-var footnoteMarkerHighlight = function(id) {
-  if (oldFootnoteId!='') 
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none';
-  oldFootnoteId = '';
-  despamEffect('FootnoteMarker'+id,'Pulsate',3)
-}
-//--&gt;
-&lt;/script&gt;
-
-<sup id="FootnoteMarker1">
-    <a shape="rect" class="FootnoteMarker" name="FootnoteMarker1" 
href="#Footnote1" onclick="footnoteHighlight(&quot;1&quot;,true);" 
alt="Footnote: Click here to display the footnote" title="Footnote: Click here 
to display the footnote">
-            1
-    </a>
-</sup>
-</p><p></p><p></p><p></p><p>.</p><p>&#160;</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="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[  &lt;t:beaneditform 
object=&quot;address&quot;
-    
reorder=&quot;honorific,firstName,lastName,street1,street2,city,state,zip,email,phone&quot;
 /&gt;
+</div></div><p>When you refresh the page, you may see the warning like the 
following at the top of the page:</p><p><img class="confluence-embedded-image" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/hmac-warning.png?version=2&amp;modificationDate=1416883285600&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/hmac-warning.png?version=2&amp;modificationDate=1416883285600&amp;api=v2"></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">
+<script class="theme: Default; brush: java; gutter: false" 
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><img class="confluence-embedded-image" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=2&amp;modificationDate=1416884366039&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/create-address-initial.png?version=2&amp;modificationDate=1416884366039&amp;api=v2"></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 u
 ser 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">
+<script class="theme: Default; brush: xml; gutter: false" 
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><img class="confluence-embedded-image" width="700" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=1&amp;modificationDate=1291928238000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/create-address-reordered.png?version=1&amp;modificationDate=1291928238000&amp;api=v2"></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 pa
 rticular 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">
+</div></div><p><img class="confluence-embedded-image" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=2&amp;modificationDate=1416884592822&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/create-address-reordered.png?version=2&amp;modificationDate=1416884592822&amp;api=v2"></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 nam
 e: 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>street1-label=Street 1
 street2-label=Street 2
 email-label=E-Mail
@@ -231,18 +156,18 @@ 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="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[  &lt;t:beaneditform submitlabel=&quot;Create 
Address&quot; object=&quot;address&quot;/&gt;
+<script class="theme: Default; brush: xml; gutter: false" 
type="syntaxhighlighter"><![CDATA[    &lt;t:beaneditform 
submitlabel=&quot;Create Address&quot; object=&quot;address&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 relabeling:</p><p><img 
class="confluence-embedded-image confluence-content-image-border" width="700" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v5.png?version=1&amp;modificationDate=1286782418000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/address-v5.png?version=1&amp;modificationDate=1286782418000&amp;api=v2"><br
 clear="none"> Create Address form with proper labels</p><p>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 referenc
 e 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="theme: Default; brush: xml; gutter: false" 
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 class="theme: Default; brush: xml; gutter: false" 
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>
 </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>At the end of the day, 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 a
 nd zip fields, adding a @Validate annotation to each:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[  @Validate(&quot;required&quot;)
-  public String firstName;
+<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[    @Validate(&quot;required&quot;)
+    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="aui-message problem shadowed information-macro">
                             <span class="aui-icon icon-problem">Icon</span>
@@ -251,15 +176,15 @@ DR=Dr.
                     </div>
     </div>
 <p>Restart the application, and refresh your browser, then hit the submit 
button.</p><p><img class="confluence-embedded-image 
confluence-content-image-border" height="482" width="760" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v6.png?version=1&amp;modificationDate=1286782418000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/address-v6.png?version=1&amp;modificationDate=1286782418000&amp;api=v2"></p><p>Form
 with client side validations visible</p><p>This is a shot just after hitting 
the submit button; all the fields have been validated and pop-up error bubbles 
are displayed. This looks a bit cluttered, but all the bubbles, except for the 
one for the focus field (the field the user is actively typing into), will fade 
out after a moment. As you tab from field to field, Tapestry will validate your 
input and briefly display the error bubble. And <em>all</em> of this is taking 
place on the client side, without any communication wi
 th the application.</p><p>Each field in error has been highlighted (it's a bit 
subtle) and marked with a red "X". 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.</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="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[  
@Validate(&quot;required,regexp=^\\d{5}(-\\d{4})?$&quot;)
-  public String zip;
+<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[    
@Validate(&quot;required,regexp=^\\d{5}(-\\d{4})?$&quot;)
+    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><img class="confluence-embedded-image 
confluence-content-image-border" width="700" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v7.png?version=1&amp;modificationDate=1286782418000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/address-v7.png?version=1&amp;modificationDate=1286782418000&amp;api=v2"><br
 clear="none"> Regexp validation</p><p>This is what you'll see after typing 
"abc" and tabbing out of the field, then tabbing back in. It's a little hard to 
capture all the animation effects in a still photo.</p><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 p
 ut 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><img 
class="confluence-embedded-image confluence-content-image-border" width="700" 
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v8.png?version=1&amp;modificationDate=1286782418000&amp;api=v2";
 
data-image-src="/confluence/download/attachments/23340431/address-v8.png?version=1&amp;modificationDate=1286782418000&amp;api=v2"></p><p>Regexp
 validation with corrected message</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" sty
 le="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[  @Validate(&quot;required,regexp&quot;)
-  public String zip;
+<script class="theme: Default; brush: java; gutter: false" 
type="syntaxhighlighter"><![CDATA[    @Validate(&quot;required,regexp&quot;)
+    public String zip;
 ]]></script>
 </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})?$


Reply via email to