tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Ajax Components FAQ
Date Tue, 22 Feb 2011 00:17:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2036/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/Ajax+Components+FAQ">Ajax
Components FAQ</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~hlship">Howard
M. Lewis Ship</a>
    </h4>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{scrollbar}
<br> <br></td></tr>
            <tr><td class="diff-unchanged" >h2. Ajax Components <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>Instead, Tapestry creates
a random-ish unique id suffix, such as &quot;12a820cc40e&quot; in the example; this
suffix is appended to all allocated ids to ensure that they do not conflict with previously
rendered ids. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
<br> <br>{scrollbar} <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/JavaScript+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/JavaScript+FAQ">JavaScript
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/Injection+FAQ">Injection
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Injection+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="AjaxComponentsFAQ-AjaxComponents"></a>Ajax Components</h2>

<p>Main article: <a href="/confluence/display/TAPESTRY/Ajax+and+Zones" title="Ajax
and Zones">Ajax and Zones</a></p>

<h3><a name="AjaxComponentsFAQ-DoIhavetospecifyboth%7B%7Bid%7D%7Dand%7B%7Bt%3Aid%7D%7DforZonecomponents%3F"></a>Do
I have to specify both <tt>id</tt> and <tt>t:id</tt> for Zone components?</h3>

<p>The examples for the Zone component (in the Component Reference) consistently specify
both <tt>id</tt> and <tt>t:id</tt> and this is probably a good idea.</p>

<p>Generally speaking, if you don't specify the client-side id (the <tt>id</tt>
attribute), it will be the same as the Tapestry component id (<tt>t:id</tt>).</p>

<p>However, there are any number of exceptions to this rule. The Zone may be rendering
inside a Loop (in which case, each rendering will have a unique client side id). The Zone
may be rendering as part of a partial page render, in which case, a random unique id is inserted
into the id. There are other examples where Tapestry component ids in nested components may
also clash.</p>

<p>The point is, to be sure, specify the exact client id.  This will be the value for
the <tt>zone</tt> parameter of the triggering component (such as a Form, PageLink,
ActionLink, etc.).</p>

<h3><a name="AjaxComponentsFAQ-HowdoIupdatethecontentofaZonefromaneventhandlermethod%3F"></a>How
do I update the content of a Zone from an event handler method?</h3>

<p>When a client-side link or form triggers an update, the return value from the event
handler method is used to construct a partial page response; this partial page response includes
markup content that is used to update the Zone's client-side <tt>&lt;div&gt;</tt>
element.</p>

<p>Where does that content come from?  You inject it into your page.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
&lt;t:zone id=<span class="code-quote">"search"</span> t:id=<span class="code-quote">"searchZone"</span>&gt;
  &lt;t:form t:id=<span class="code-quote">"searchForm"</span> zone=<span
class="code-quote">"searchZone"</span>&gt;
    &lt;t:textfield t:id=<span class="code-quote">"query"</span> size=<span
class="code-quote">"20"</span>/&gt;
    &lt;input type=<span class="code-quote">"submit"</span> value=<span
class="code-quote">"Search"</span>/&gt;
  &lt;/t:form&gt;
&lt;/t:zone&gt;

&lt;t:block id=<span class="code-quote">"searchResults"</span>&gt;
  &lt;ul&gt;
    &lt;li t:type=<span class="code-quote">"loop"</span> source=<span class="code-quote">"searchHits"</span>
value=<span class="code-quote">"searchHit"</span>&gt;${searchHit}&lt;/li&gt;
  &lt;/ul&gt;
&lt;/t:block&gt;
</pre>
</div></div>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Inject
  <span class="code-keyword">private</span> Block searchResults;

  <span class="code-object">Object</span> onSuccessFromSearchForm()
  {
    searchHits = searchService.performSearch(query);

    <span class="code-keyword">return</span> searchResults;
  }
</pre>
</div></div>

<p>So, when the search form is submitted, the resulting search hits are collected. 
In the same request, the searchResults block is rendered, package, and sent to the client.
 The form inside the client-side Zone <tt>&lt;div&gt;</tt> is replaced
with the list of hits.</p>

<p>In many cases, you just want to re-render the Zone itself, to display updated content.
 In that case, you don't need a separate <tt>&lt;t:block&gt;</tt>, instead
you can use @InjectComponent to inject the Zone object itself, and return the Zone's body:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @InjectComponent
  <span class="code-keyword">private</span> Zone statusZone;

  <span class="code-object">Object</span> onActionFromUpdateStatus()
  {
    <span class="code-keyword">return</span> statusZone.getBody();
  }
</pre>
</div></div>

<h3><a name="AjaxComponentsFAQ-HowtoIupdatemultiplezonesinasingleeventhandler%3F"></a>How
to I update multiple zones in a single event handler?</h3>

<p>To do this, you must know, on the server, the client ids of each Zone. That's one
of the reasons that you will generally set the Zone's client id (via the Zone's id parameter),
rather than let Tapestry assign a client id for you.</p>

<p>From the event handler method, instead of returning a Block or a Component, return
a multi-zone update:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Inject
  <span class="code-keyword">private</span> Block searchResults;

  @Inject
  <span class="code-keyword">private</span> Block statusBlock;

  <span class="code-object">Object</span> onSuccessFromSearchForm()
  {
    searchHits = searchService.performSearch(query);

    message = <span class="code-object">String</span>.format(<span class="code-quote">"Found
%,d matching documents"</span>, searchHits.size());

    <span class="code-keyword">return</span> <span class="code-keyword">new</span>
MultiZoneUpdate(<span class="code-quote">"results"</span>, searchResults).add(<span
class="code-quote">"status"</span>, statusBlock);
  }
</pre>
</div></div>

<h3><a name="AjaxComponentsFAQ-What%27sthatweirdnumberinthemiddleoftheclientidsafteraZoneisupdated%3F"></a>What's
that weird number in the middle of the client ids after a Zone is updated?</h3>

<p>You might start with markup in your template for a component such as a TextField:</p>

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

<p>When the component initially renders as part of a full page render, you get a sensible
bit of markup:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  &lt;input id=<span class="code-quote">"firstName"</span> name=<span class="code-quote">"firstName"</span>
type=<span class="code-quote">"text"</span>&gt;
</pre>
</div></div>

<p>But when the form is inside a Zone and rendered as part of a zone update, the ids
get weird:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   &lt;input id=<span class="code-quote">"firstName_12a820cc40e"</span> name=<span
class="code-quote">"firstName"</span> type=<span class="code-quote">"text"</span>&gt;
</pre>
</div></div>

<p>What's happening here is that Tapestry is working to prevent unwanted id clashes
as part of the page update.  In an HTML document, each <tt>id</tt> is expected
to be unique; most JavaScript is keyed off of the <tt>id</tt> field, for instance.</p>

<p>In a full page render, components don't just use their component id (<tt>t:id</tt>)
as their client id; instead they use the <tt>JavaScriptSupport</tt> environmental
to allocate a unique id. When there's no loops or conflicts, the client id matches the component
id.</p>

<p>When the component is inside a loop, a suffix is appended:  <tt>firstName</tt>,
<tt>firstName_0</tt>, <tt>firstName_1</tt>, etc.</p>

<p>When the component is rendered as part of an Ajax partial page update, the rules
are different. Since Tapestry doesn't know what content has been rendered onto the page previously,
it can't use its normal tricks to ensure that ids are unique.</p>

<p>Instead, Tapestry creates a random-ish unique id suffix, such as "12a820cc40e" in
the example; this suffix is appended to all allocated ids to ensure that they do not conflict
with previously rendered ids.</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/JavaScript+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/JavaScript+FAQ">JavaScript
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/Injection+FAQ">Injection
FAQ</a></td><td class='ScrollbarNextIcon'><a href="/confluence/display/TAPESTRY/Injection+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/Ajax+Components+FAQ">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23334985&revisedVersion=15&originalVersion=14">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message