tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Forms and Form Components FAQ
Date Sat, 04 Jun 2011 19:13:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Forms+and+Form+Components+FAQ">Forms
and Form Components FAQ</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~bobharner">Bob
Harner</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Renamed. Most or all FAQ pages should have FAQ at the end of their names for clarity<br
/>
    </div>
        <br/>
                         <h4>Changes (0)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <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
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Page+And+Component+Classes+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Page+And+Component+Classes+FAQ">Page
And Component Classes FAQ</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions">Frequently Asked Questions</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/BeanEditForm+FAQ">BeanEditForm
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/BeanEditForm+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>

<h2><a name="FormsandFormComponentsFAQ-FormsandFormComponents"></a>Forms
and Form Components</h2>

<h3><a name="FormsandFormComponentsFAQ-Whatisthe%7B%7Bt%3Aformdata%7D%7Dhiddenfieldfor%3F"></a>What
is the <tt>t:formdata</tt> hidden field for?</h3>

<p>In Tapestry, rendering a form can be a complicated process; inside the body of the
Form component are many of field components: TextField, Select, TextArea, and so forth. Each
of these must pull data out of your data model and convert it to the string form used inside
the client web browser.  In addition, JavaScript to support client-side validation must be
generated.  This can be further complicated by the use of Loop and If components, or made
really complicated by the use of Block (to render portions of other pages: this is what the
BeanEditForm component does).</p>

<p>Along the way, the Form is generating unique form control names for each field component,
as it renders.</p>

<p>When the client-side Form is submitted, an event is triggered on the server-side
Form component. It now needs to locate each component, in turn, inform the component of its
control name, and allow the component to read the corresponding query parameter. The component
then converts the client-side string back into a server-side value and performs validations
before updating the data model.</p>

<p>That's where <tt>t:formdata</tt> comes in.  While components are rendering,
they are using the FormSupport environmental object to record callbacks:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>FormSupport.java (partial)</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
FormSupport <span class="code-keyword">extends</span> ClientElement
{
    /**
     * Stores an action <span class="code-keyword">for</span> execution during
a later request.  If the action contains any mutable state, it should be in
     * its <span class="code-keyword">final</span> state before invoking <span
class="code-keyword">this</span> method and its internal state should not be changed
subsequently.
     */
    &lt;T&gt; void store(T component, ComponentAction&lt;T&gt; action);

    /**
     * As with {@link #store(<span class="code-object">Object</span>, org.apache.tapestry5.ComponentAction)}},
but the action is also invoked
     * immediately. This is useful <span class="code-keyword">for</span> defining
an action that should occur symmetrically in both the render request and
     * the form submission's event request.
     *
     * @param component component against which to trigger the action
     * @param action    the action that will be triggered (and passed the component)
     */
    &lt;T&gt; void storeAndExecute(T component, ComponentAction&lt;T&gt; action);
</pre>
</div></div>

<p>The <tt>ComponentAction</tt> objects are the callbacks.  <tt>t:formdata</tt>
is simply an object stream of these callbacks, compressed and encoded in Base64.  When using
Ajax, you may see multiple <tt>t:formdata</tt> hidden fields (they are processed
one after another).</p>


<h3><a name="FormsandFormComponentsFAQ-HowdoIchangethelabelforafieldonthefly%3F"></a>How
do I change the label for a field on the fly?</h3>


<p>Tapestry tries to be smart about generating the label string for a field.  It has
some smart default logic, first checking for the <em>component-id</em><tt>-label</tt>
in the container's message catalog, then ultimately converting the component's id into a user-presentable
label.</p>

<p>You can override the label in two ways:</p>

<p>First, you can supply a body to the <tt>Label</tt> component:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  &lt;t:label <span class="code-keyword">for</span>=<span class="code-quote">"username"</span>&gt;${usernameLabel}&lt;/t:label&gt;
  &lt;t:textfield t:id=<span class="code-quote">"username"</span>/&gt;
</pre>
</div></div>

<p>Here, the component class must provide a <tt>usernameLabel</tt> property.
That property becomes the text of the label. An implementation of the property might look
something like:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  <span class="code-keyword">public</span> <span class="code-object">String</span>
getUsernameLabel()
  {
    <span class="code-keyword">return</span> systemPreferences.useEmailAddressForUserName()
? <span class="code-quote">"Email address"</span> : <span class="code-quote">"User
name"</span>;
  }
</pre>
</div></div>

<p>However, if there are any validations on the field, the error message will include
the default label (as discussed above).</p>

<p>To uniformly update the label both on the page, and in any validation messages, bind
the TextField's <tt>label</tt> parameter:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  &lt;t:label <span class="code-keyword">for</span>=<span class="code-quote">"username"</span>/&gt;
  &lt;t:textfield t:id=<span class="code-quote">"username"</span> label=<span
class="code-quote">"prop:usernameLabel"</span>/&gt;
</pre>
</div></div>

<p>The "prop:" prefix identifies that "usernameLabel" is to be interpreted as a property
expression (normally, the binding for the <tt>label</tt> parameter is interpreted
as a string literal).  The Label component gets the text it displays from the TextField component,
and the TextField component uses the same text when generating server-side and client-side
validation messages.</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
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Page+And+Component+Classes+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Page+And+Component+Classes+FAQ">Page
And Component Classes FAQ</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Frequently+Asked+Questions">Frequently Asked Questions</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/TAPESTRY/BeanEditForm+FAQ">BeanEditForm
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/BeanEditForm+FAQ"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Forms+and+Form+Components+FAQ">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23335294&revisedVersion=7&originalVersion=6">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message