tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Ajax and Zones
Date Sat, 02 Feb 2013 11:52: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/Ajax+and+Zones">Ajax
and Zones</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>
        Mentioned ajaxResponseRenderer and added links to JumpStart, rearranged a bit<br
/>
    </div>
        <br/>
                         <h4>Changes (29)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{float} <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Tapestry
provides easy-to-use support for *Ajax*, the technique of using JavaScript to dynamically
updating parts of a web page with content from the server without redrawing the whole page.
But with Tapestry, you don&#39;t have to write any JavaScript code. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Tapestry
provides easy-to-use support for *Ajax*, the technique of using JavaScript to dynamically
updating parts of a web page with content from the server without redrawing the whole page.
With Tapestry, you can do simple Ajax updates without having to write any JavaScript code
at all. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" >Ajax support is included in many
[built-in components|Component Reference] and [component mixins|Component <span class="diff-changed-words">Mixins]<span
class="diff-added-chars"style="background-color: #dfd;"> via the {{zone}} parameter</span>.</span>
<br></td></tr>
            <tr><td class="diff-unchanged" > <br>h2. Zones <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >A Zone can be updated via an EventLink,
ActionLink or Select component, or by a Form. All of these components support a zone parameter,
which provides the id of the Zone&#39;s &lt;div&gt;. Clicking such a link will
invoke an event handler method on the server as normal ... except that the return value of
the event handler method is used to send a _partial page response_ to the client, and the
content of that response is used to update the Zone&#39;s &lt;div&gt; in place.
<br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h3.
An Update div within a Zone div <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{code:xml}
<br>&lt;t:actionlink t:id=&quot;someLink&quot; zone=&quot;myzone&quot;&gt;update&lt;/t:actionlink&gt;
<br>... <br>&lt;t:zone t:id=&quot;myZone&quot; id=&quot;myzone&quot;&gt;
<br>    The current time is ${currentTime} <br>&lt;/t:zone&gt; <br>{code}
<br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">{deprecated}_This
feature is removed starting with Tapestry 5.4_{deprecated} <br> <br>In many situations,
a Zone is a kind of &quot;wrapper&quot; or &quot;container&quot; for dynamic
content; one that provides a look and feel ... a bit of wrapping markup to create a border.
In that situation, the Zone &lt;div&gt; may contain an update &lt;div&gt;.
<br> <br>An Update &lt;div&gt; is specifically a &lt;div&gt; element
marked with the CSS class &quot;t-zone-update&quot;, _inside_ the Zone&#39;s &lt;div&gt;.
<br> <br>If an Update div exists within a Zone div, then when Tapestry updates
a zone only the update &lt;div&gt;&#39;s content will be changed, rather than
the entire Zone &lt;div&gt;. <br> <br>The show and update functions (see
Zone Functions, below) apply to the Zone &lt;div&gt;, not just the update &lt;div&gt;.
<br> <br></td></tr>
            <tr><td class="diff-unchanged" >h3. Event Handler Return Types <br>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{float:right|background=#eee|padding=0
1em} <br>    *JumpStart Demo:* <br>    [AJAX ActionLink|http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/actionlink]
<br>{float} <br> <br></td></tr>
            <tr><td class="diff-unchanged" >In a traditional request, the return
value of an event handler method is used to determine which page will render a _complete_
response, and a _redirect_ is sent to the client to render the new page (as a new request).
<br> <br>In contrast, with a Zone update, the return value is used to render a
_partial response_ within the _same request_. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >This return value is <span
class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">typically</span>
<span class="diff-added-words"style="background-color: #dfd;">often just the zone&#39;s
own body (as below), but it can also be</span> an injected component or block. The value
will be rendered, and that markup will be used on the client side to update the Zone&#39;s
&lt;div&gt;. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Alternatively,
an event handler may return a [Link|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html]
and the client will be redirected to that link.  Similarly, returning a page name (as a String),
or a page class, or a page instance will send a redirect to the indicated page. <br>
<br>h3. Multiple Zone Updates <br> <br>An event handler may cause multiple
zones to be updated on the client side. To accomplish this, return a [MultiZoneUpdate|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ajax/MultiZoneUpdate.html]
object configured with the zones to update. You must know the client-side id for each zone
to update (the best way for this is to lock down the zone&#39;s id using the id parameter
of the Zone component). <br> <br>The renderer for each zone can be a block or
component, or a [Renderable|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Renderable.html]
or [RenderCommand|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/RenderCommand.html]
... or an object, such as String, that can be coerced to either of these. Typically, you will
inject a Block or Component and return that: <br> <br></td></tr>
            <tr><td class="diff-unchanged" >{code:java} <br>@Inject <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">private
Form registrationForm; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">private
Request request; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">@Inject
Block registrationHelp; <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> <span class="diff-added-words"style="background-color: #dfd;">@InjectComponent</span>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">private
Zone myZone; <br>... <br></td></tr>
            <tr><td class="diff-changed-lines" >Object <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">onActionFromRegister()</span>
<span class="diff-added-words"style="background-color: #dfd;">onClickFromSomeLink()</span>
<br></td></tr>
            <tr><td class="diff-unchanged" >{ <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
   return new MultiZoneUpdate(&quot;userInput&quot;, registrationForm).add(&quot;helpPanel&quot;,
registrationHelp); <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
  return myZone.getBody(); // AJAX request, return zone&#39;s own body <br></td></tr>
            <tr><td class="diff-unchanged" >}  <br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">This
implies that there are two zones, &quot;userInput&quot; and &quot;helpPanel&quot;,
somewhere in the rendered page, waiting to receive the updated content. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Alternatively,
an event handler may return a [Link|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html]
and the client will be redirected to that link.  Similarly, returning a page name (as a String),
or a page class, or a page instance will send a redirect to the indicated page. <br></td></tr>
            <tr><td class="diff-unchanged" > <br>h3. Graceful Degradation
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>@InjectComponent <br></td></tr>
            <tr><td class="diff-changed-lines" >private Zone <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">zone;</span>
<span class="diff-added-words"style="background-color: #dfd;">myZone;</span> <br></td></tr>
            <tr><td class="diff-unchanged" >... <br>Object onClickFromSomeLink()
<br>{ <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
   if(request.isXHR()) <br>    { <br>       return zone.getBody(); // AJAX request,
return zone body <br>    } <br>    else <br>    { <br>       return
null; // non-AJAX request, redraw current page <br>    } <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
   // return either the zone body (ajax) or whole page (non-ajax) <br>    return request.isXHR()
? myZone.getBody() : null; <br></td></tr>
            <tr><td class="diff-unchanged" >}  <br>{code} <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
Multiple Zone Updates <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{float:right|background=#eee|padding=0
1em} <br>    *JumpStart Demo:* <br>    [AJAX Multiple Zone Update|http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/multiplezoneupdate]
<br>{float} <br> <br>An event handler often needs to update multiple zones
on the client side. To accomplish this, use an [AjaxResponseRenderer|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.html]
(or, for Tapestry 5.2 and earlier, return a [MultiZoneUpdate|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ajax/MultiZoneUpdate.html]
object), indicating the zones to update. You must know the client-side id for each zone to
update (the best way for this is to lock down the zone&#39;s id using the id parameter
of the Zone component). <br> <br>The renderer for each zone can be a block or
component, or a [Renderable|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Renderable.html]
or [RenderCommand|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/RenderCommand.html]
... or an object, such as String, that can be coerced to either of these. Typically, you will
inject a Block or Component and return that: <br> <br>{section} <br>{column}
<br>{code:java|title=For Tapestry 5.3 and later} <br>@InjectComponent <br>private
Zone userInput; <br> <br>@InjectComponent <br>private Zone helpPanel; <br>
<br>@Inject <br>private AjaxResponseRenderer ajaxResponseRenderer; <br>
<br>void onActionFromRegister() <br>{ <br>    ajaxResponseRenderer.addRender(&quot;userInput&quot;,
userInput) <br>                .addRender(&quot;helpPanel&quot;, helpPanel);
<br>} <br>{code} <br>{column} <br> <br>{column} <br>{code:java|title=For
Tapestry 5.1, 5.2 and 5.3} <br>@Inject <br>private Form registrationForm; <br>
<br>@Inject Block registrationHelp; <br> <br>Object onActionFromRegister()
<br>{ <br>    return new MultiZoneUpdate(&quot;userInput&quot;, registrationForm)
<br>                .add(&quot;helpPanel&quot;, registrationHelp); <br>}
<br>{code} <br>&amp;nbsp; &amp;nbsp; _Note that MultiZoneUpdate is deprecated
starting with Tapestry 5.3._ <br> <br> <br>{column} <br>{section}
<br> <br>These examples assume that there are two zones, &quot;userInput&quot;
and &quot;helpPanel&quot;, somewhere in the rendered page, waiting to receive the
updated content. <br> <br>h3. An Update div within a Zone div <br> <br>{deprecated}_This
feature is removed starting with Tapestry 5.4_{deprecated} <br> <br>In many situations,
a Zone is a kind of &quot;wrapper&quot; or &quot;container&quot; for dynamic
content; one that provides a look and feel ... a bit of wrapping markup to create a border.
In that situation, the Zone &lt;div&gt; may contain an update &lt;div&gt;.
<br> <br>An Update &lt;div&gt; is specifically a &lt;div&gt; element
marked with the CSS class &quot;t-zone-update&quot;, _inside_ the Zone&#39;s &lt;div&gt;.
<br> <br>If an Update div exists within a Zone div, then when Tapestry updates
a zone only the update &lt;div&gt;&#39;s content will be changed, rather than
the entire Zone &lt;div&gt;. <br> <br>The show and update functions (see
Zone Functions, below) apply to the Zone &lt;div&gt;, not just the update &lt;div&gt;.
<br> <br></td></tr>
            <tr><td class="diff-unchanged" >h3. Zone Effect Functions <br>
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{code} <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
Zone Component Id vs. Zone Element Id <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2.
Zone Component Id vs. Zone Element Id <br> <br></td></tr>
            <tr><td class="diff-unchanged" >Like all Tapestry components, Zones
have a component id, specified using the {{t:id}} attribute.  If you do not assign a component
id, a unique id is assigned by Tapestry. <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >The show and update function names
are converted to lower case; all the methods of Tapestry.ElementEffect should have all lower-case
names. Because client-side JavaScript is so fluid (new methods may be added to existing objects),
Tapestry makes no attempt to validate the function names ... however, if the names are not
valid, then the default show and highlight methods will be used. <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h3.
Frequently Asked Questions <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
More Information <br></td></tr>
            <tr><td class="diff-unchanged" > <br>For examples of extending
a Form with a Zone and updating multiple zones at once, see the [Ajax Components FAQ]. <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >h2. Autocomplete Mixin <br>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{float:right|background=#eee|padding=0
1em} <br>    *JumpStart Demo:* <br>    [Autocomplete Mixin|http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/autocompletemixin]
<br>{float} <br> <br></td></tr>
            <tr><td class="diff-unchanged" >The [Autocomplete|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/mixins/Autocomplete.html]
mixin exists to allow a text field to query the server for completions for a partially entered
phrase. It is often used in situations where the field exists to select a single value from
a large set, too large to successfully download to the client as a drop down list; for example,
when the number of values to select from is numbered in the thousands. <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <div class='navmenu' style='float:right; background:#eee; margin:3px; padding:3px'><table
class="tableview" width="100%">
            <tr><th style="padding: 3px 3px 3px 0px">Related Articles</th></tr>
                        <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Ajax+and+Zones">Ajax
and Zones</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/JavaScript">JavaScript</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/JavaScript+FAQ">JavaScript
FAQ</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Ajax+Components+FAQ">Ajax
Components FAQ</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Assets">Assets</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Component+Cheat+Sheet">Component
Cheat Sheet</a>
        
                                            </td>
        </tr>
            </table>
</div>

<p>Tapestry provides easy-to-use support for <b>Ajax</b>, the technique
of using JavaScript to dynamically updating parts of a web page with content from the server
without redrawing the whole page. With Tapestry, you can do simple Ajax updates without having
to write any JavaScript code at all.</p>

<p>Ajax support is included in many <a href="/confluence/display/TAPESTRY/Component+Reference"
title="Component Reference">built-in components</a> and <a href="/confluence/display/TAPESTRY/Component+Mixins"
title="Component Mixins">component mixins</a> via the <tt>zone</tt> parameter.</p>

<h2><a name="AjaxandZones-Zones"></a>Zones</h2>

<p>Zones are Tapestry's approach to performing partial page updates. A <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Zone.html"
class="external-link" rel="nofollow">Zone component</a> renders as an HTML element,
typically a &lt;div&gt;, with the "t-zone" CSS class. (It also adds some JavaScript
to the page to "wire up" a Tapestry.ZoneManager object to control updating that element.)</p>

<p>A Zone can be updated via an EventLink, ActionLink or Select component, or by a Form.
All of these components support a zone parameter, which provides the id of the Zone's &lt;div&gt;.
Clicking such a link will invoke an event handler method on the server as normal ... except
that the return value of the event handler method is used to send a <em>partial page
response</em> to the client, and the content of that response is used to update the
Zone's &lt;div&gt; in place.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;t:actionlink t:id=<span class="code-quote">"someLink"</span>
zone=<span class="code-quote">"myzone"</span>&gt;</span>update<span
class="code-tag">&lt;/t:actionlink&gt;</span>
...
<span class="code-tag">&lt;t:zone t:id=<span class="code-quote">"myZone"</span>
id=<span class="code-quote">"myzone"</span>&gt;</span>
    The current time is ${currentTime}
<span class="code-tag">&lt;/t:zone&gt;</span>
</pre>
</div></div>

<h3><a name="AjaxandZones-EventHandlerReturnTypes"></a>Event Handler Return
Types</h3>

<div class='navmenu' style='float:right; background:#eee; margin:3px; padding:0 1em'><p>
   <b>JumpStart Demo:</b><br/>
    <a href="http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/actionlink"
class="external-link" rel="nofollow">AJAX ActionLink</a></p></div>

<p>In a traditional request, the return value of an event handler method is used to
determine which page will render a <em>complete</em> response, and a <em>redirect</em>
is sent to the client to render the new page (as a new request).</p>

<p>In contrast, with a Zone update, the return value is used to render a <em>partial
response</em> within the <em>same request</em>.</p>

<p>This return value is often just the zone's own body (as below), but it can also be
an injected component or block. The value will be rendered, and that markup will be used on
the client side to update the Zone's &lt;div&gt;.</p>

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

@InjectComponent
<span class="code-keyword">private</span> Zone myZone;
...
<span class="code-object">Object</span> onClickFromSomeLink()
{
   <span class="code-keyword">return</span> myZone.getBody(); <span class="code-comment">//
AJAX request, <span class="code-keyword">return</span> zone's own body
</span>} 
</pre>
</div></div>

<p>Alternatively, an event handler may return a <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html"
class="external-link" rel="nofollow">Link</a> and the client will be redirected to
that link.  Similarly, returning a page name (as a String), or a page class, or a page instance
will send a redirect to the indicated page.</p>

<h3><a name="AjaxandZones-GracefulDegradation"></a>Graceful Degradation</h3>

<p>Users who do not have JavaScript enabled may click EventLinks (or ActionLinks, or
Forms) that are configured to update a Zone. When that occurs, the request will still be sent
to the server, but Tapestry will handle it as a <em>traditional</em> request.</p>

<p>To support graceful degradation, you should detect that case in your event handler
method and return a traditional response: a page, page name or page class. This is accomplished
by injecting the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Request.html"
class="external-link" rel="nofollow">Request</a> object, and invoking the isXHR()
method. This value will be true for Ajax requests, and false for traditional request.</p>

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

@InjectComponent
<span class="code-keyword">private</span> Zone myZone;
...
<span class="code-object">Object</span> onClickFromSomeLink()
{
    <span class="code-comment">// <span class="code-keyword">return</span>
either the zone body (ajax) or whole page (non-ajax)
</span>    <span class="code-keyword">return</span> request.isXHR() ? myZone.getBody()
: <span class="code-keyword">null</span>;
} 
</pre>
</div></div>

<h3><a name="AjaxandZones-MultipleZoneUpdates"></a>Multiple Zone Updates</h3>

<div class='navmenu' style='float:right; background:#eee; margin:3px; padding:0 1em'><p>
   <b>JumpStart Demo:</b><br/>
    <a href="http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/multiplezoneupdate"
class="external-link" rel="nofollow">AJAX Multiple Zone Update</a></p></div>

<p>An event handler often needs to update multiple zones on the client side. To accomplish
this, use an <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.html"
class="external-link" rel="nofollow">AjaxResponseRenderer</a> (or, for Tapestry 5.2
and earlier, return a <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ajax/MultiZoneUpdate.html"
class="external-link" rel="nofollow">MultiZoneUpdate</a> object), indicating the
zones to update. You must know the client-side id for each zone to update (the best way for
this is to lock down the zone's id using the id parameter of the Zone component).</p>

<p>The renderer for each zone can be a block or component, or a <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Renderable.html"
class="external-link" rel="nofollow">Renderable</a> or <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/RenderCommand.html"
class="external-link" rel="nofollow">RenderCommand</a> ... or an object, such as
String, that can be coerced to either of these. Typically, you will inject a Block or Component
and return that:</p>

<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0" width="100%"><tbody><tr>
<td class="confluenceTd" valign="top">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>For Tapestry 5.3 and later</b></div><div
class="codeContent panelContent">
<pre class="code-java">
@InjectComponent
<span class="code-keyword">private</span> Zone userInput;

@InjectComponent
<span class="code-keyword">private</span> Zone helpPanel;

@Inject
<span class="code-keyword">private</span> AjaxResponseRenderer ajaxResponseRenderer;

void onActionFromRegister()
{
    ajaxResponseRenderer.addRender(<span class="code-quote">"userInput"</span>,
userInput)
                .addRender(<span class="code-quote">"helpPanel"</span>, helpPanel);
}
</pre>
</div></div></td>

<td class="confluenceTd" valign="top">
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>For Tapestry 5.1, 5.2 and 5.3</b></div><div
class="codeContent panelContent">
<pre class="code-java">
@Inject
<span class="code-keyword">private</span> Form registrationForm;

@Inject Block registrationHelp;

<span class="code-object">Object</span> onActionFromRegister()
{
    <span class="code-keyword">return</span> <span class="code-keyword">new</span>
MultiZoneUpdate(<span class="code-quote">"userInput"</span>, registrationForm)
                .add(<span class="code-quote">"helpPanel"</span>, registrationHelp);
}
</pre>
</div></div>
<p>&nbsp; &nbsp; <em>Note that MultiZoneUpdate is deprecated starting
with Tapestry 5.3.</em></p>

</td></tr></tbody></table>

<p>These examples assume that there are two zones, "userInput" and "helpPanel", somewhere
in the rendered page, waiting to receive the updated content.</p>

<h3><a name="AjaxandZones-AnUpdatedivwithinaZonediv"></a>An Update div within
a Zone div</h3>



<div style="border-right: 20px solid #ffcccc;border-left: 20px solid #ffcccc;"><p><em>This
feature is removed starting with Tapestry 5.4</em></p></div>

<p>In many situations, a Zone is a kind of "wrapper" or "container" for dynamic content;
one that provides a look and feel ... a bit of wrapping markup to create a border. In that
situation, the Zone &lt;div&gt; may contain an update &lt;div&gt;.</p>

<p>An Update &lt;div&gt; is specifically a &lt;div&gt; element marked
with the CSS class "t-zone-update", <em>inside</em> the Zone's &lt;div&gt;.</p>

<p>If an Update div exists within a Zone div, then when Tapestry updates a zone only
the update &lt;div&gt;'s content will be changed, rather than the entire Zone &lt;div&gt;.</p>

<p>The show and update functions (see Zone Functions, below) apply to the Zone &lt;div&gt;,
not just the update &lt;div&gt;.</p>

<h3><a name="AjaxandZones-ZoneEffectFunctions"></a>Zone Effect Functions</h3>

<p>A Zone may be initially visible or invisible. When a Zone is updated, it is made
visible if not currently so. This is accomplished via a function on the Tapestry.ElementEffect
client-side object. By default, the show() function is used for this purpose. If you want
Tapestry to call a different Tapestry.ElementEffect function when updates occur, specify its
name with the zone's show parameter.</p>

<p>If a Zone is already visible, then a different effect function is used to highlight
the change. By default, the highlight() function is called, which performs a yellow fade to
highlight that the content of the Zone has changed. Alternatively, you can specify a different
effect function with the Zone's update parameter:</p>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Tapestry.ElementEffect Function </th>
<th class='confluenceTh'> Result </th>
</tr>
<tr>
<td class='confluenceTd'> highlight() </td>
<td class='confluenceTd'> (the default) highlight changes to an already-visible zone
</td>
</tr>
<tr>
<td class='confluenceTd'> show() </td>
<td class='confluenceTd'> make the zone visible if it isn't already visible </td>
</tr>
<tr>
<td class='confluenceTd'> slidedown() </td>
<td class='confluenceTd'> scroll the content down </td>
</tr>
<tr>
<td class='confluenceTd'> slideup() </td>
<td class='confluenceTd'> slide the content back up (opposite of slidedown) </td>
</tr>
<tr>
<td class='confluenceTd'> fade() </td>
<td class='confluenceTd'> fade the content out (opposite of show) </td>
</tr>
</tbody></table>
</div>


<p>To have Tapestry update a zone without the usual yellow highlight effect, just specify
"show" for the update parameter:</p>

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

<p>You may also define and use your own JavaScript effect function (with lower-case
names), like this:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-javascript">
Tapestry.ElementEffect.myeffectname = <span class="code-keyword">function</span>(element){
YourJavascriptCodeGoesHere; };
</pre>
</div></div>

<h3><a name="AjaxandZones-ZoneComponentIdvs.ZoneElementId"></a>Zone Component
Id vs. Zone Element Id</h3>

<p>Like all Tapestry components, Zones have a component id, specified using the <tt>t:id</tt>
attribute.  If you do not assign a component id, a unique id is assigned by Tapestry.</p>

<p>However, to coordinate things on the client side, it is necessary for components
that wish to update the zone know the <em>client-side element id</em>.  This is
specified with the <tt>id</tt> parameter of the Zone component.  If the <tt>id</tt>
parameter is not bound, then a unique value (for the current page and render) is generated
by Tapestry and this value is difficult to predict. The actual value will be available as
the <tt>clientId</tt> property of the Zone component itself.</p>

<p>Remember that the component id (<tt>t:id</tt>) is used to <em>inject</em>
the Zone component into the containing page or component. The<br/>
client-side id (<tt>id</tt>) is used ... on the client side to orchestrate requests
and updates.  You will often seen the following construct:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;t:zone t:id=<span class="code-quote">"myZone"</span>
id=<span class="code-quote">"myzone"</span>&gt;</span> ... <span
class="code-tag">&lt;/t:zone&gt;</span>

<span class="code-tag">&lt;t:actionlink t:id=<span class="code-quote">"update"</span>
zone=<span class="code-quote">"myzone"</span>&gt;</span>update<span
class="code-tag">&lt;/t:actionlink&gt;</span>
</pre>
</div></div>




<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><b>Added in
5.2</b><br /></td></tr></table></div>
<div style="border-right: 20px solid #D8E4F1;border-left: 20px solid #D8E4F1;">
<p>If the Form or Link is enclosed by the Zone itself, then the <tt>zone</tt>
parameter may be set to the special value <tt>^</tt>. The carat is evaluated,
on the client side, by searching up form the form or link element for the first enclosing
element with the <tt>t-zone</tt> CSS class. In this way, the client-side coordination
can occur without having to know what the specific client-side id of the Zone is. Because
of this, in many cases, it is no longer necessary to specify the Zone's <tt>id</tt>
parameter.</p>
</div>


<h3><a name="AjaxandZones-ZoneLimitations"></a>Zone Limitations</h3>

<p>Unlike many other situations, Tapestry relies on you to specify useful and unique
ids to Zone components, then reference those ids inside EventLink (or ActionLink, or Form)
components. Using Zone components inside any kind of loop may cause additional problems, as
Tapestry will <em>uniqueify</em> the client id you specify (appending an index
number).</p>

<p>The show and update function names are converted to lower case; all the methods of
Tapestry.ElementEffect should have all lower-case names. Because client-side JavaScript is
so fluid (new methods may be added to existing objects), Tapestry makes no attempt to validate
the function names ... however, if the names are not valid, then the default show and highlight
methods will be used.</p>

<h3><a name="AjaxandZones-MoreInformation"></a>More Information</h3>

<p>For examples of extending a Form with a Zone and updating multiple zones at once,
see the <a href="/confluence/display/TAPESTRY/Ajax+Components+FAQ" title="Ajax Components
FAQ">Ajax Components FAQ</a>.</p>

<p><a name="AjaxandZones-autocomplete"></a></p>
<h2><a name="AjaxandZones-AutocompleteMixin"></a>Autocomplete Mixin</h2>

<div class='navmenu' style='float:right; background:#eee; margin:3px; padding:0 1em'><p>
   <b>JumpStart Demo:</b><br/>
    <a href="http://jumpstart.doublenegative.com.au/jumpstart/examples/ajax/autocompletemixin"
class="external-link" rel="nofollow">Autocomplete Mixin</a></p></div>

<p>The <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/mixins/Autocomplete.html"
class="external-link" rel="nofollow">Autocomplete</a> mixin exists to allow a text
field to query the server for completions for a partially entered phrase. It is often used
in situations where the field exists to select a single value from a large set, too large
to successfully download to the client as a drop down list; for example, when the number of
values to select from is numbered in the thousands.</p>

<p>Autocomplete can be added to an existing text field:</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">"accountName"</span> t:mixins=<span
class="code-quote">"autocomplete"</span> size=<span class="code-quote">"100"</span>/&gt;
</pre>
</div></div>

<p>The mixin can be configured in a number of ways, see the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/mixins/Autocomplete.html"
class="external-link" rel="nofollow">component reference</a>.</p>

<p>When the user types into the field, the client-side JavaScript will send a request
to the server to get completions.</p>

<p>You must write an event handler to provide these completions. The name of the event
is "providecompletions". The context is the partial input value, and the return value will
be converted into the selections for the user.</p>

<p>For example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  List&lt;<span class="code-object">String</span>&gt; onProvideCompletionsFromAccountName(<span
class="code-object">String</span> partial)
  {
    List&lt;Account&gt; matches = accountDAO.findByPartialAccountName(partial);

    List&lt;<span class="code-object">String</span>&gt; result = <span
class="code-keyword">new</span> ArrayList&lt;<span class="code-object">String</span>&gt;();

    <span class="code-keyword">for</span> (Account a : matches)
    {
      result.add(a.getName());
    }

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

<p>This presumes that <tt>findByPartialAccountName()</tt> will sort the
values, otherwise you will probably want to sort them. The Autocomplete mixin does <em>not</em>
do any sorting.</p>

<p>You can return an object array, a list, even a single object. You may return objects
instead of strings ... and <tt>toString()</tt> will be used to convert them into
client-side strings.</p>

<p>Tapestry's default stylesheet includes entries for controlling the look of the floating
popup of selections.</p>

<p>You may override <tt>DIV.t-autocomplete-menu UL</tt> to change the main
look and feel, <tt>DIV.t-autocomplete-menu LI</tt> for a normal item in the popup
list, and <tt>DIV.t-autocomplete-menu LI.selected</tt> for the element under the
cursor (or selecting using the arrow keys).</p>

<h1><a name="AjaxandZones-YourownAjaxComponents"></a>Your own Ajax Components</h1>

<p>A study of the Autocomplete mixin's <a href="http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java?view=markup"
class="external-link" rel="nofollow">source code</a> should be very helpful: it shows
how to ask the ComponentResources object to create a link.</p>

<p>The key part is the way Tapestry invokes a component event handler method on the
component.</p>

<p>For an Ajax request, the return value from an event handler method is processed differently
than for a traditional action request. In an normal request, the return value is the normally
name of a page (to redirect to), or the Class of a page to redirect to, or an instance of
a page to redirect to.</p>

<p>For an Ajax request, a redirect is not sent: any response is rendered as part of
the same request and sent back immediately.</p>

<p>The possible return values are:</p>

<ul>
	<li>A Block or Component to render as the response. The response will be a JSON hash,
with a "content" key whose value is the rendered markup. This is the basis for updates with
the Zone component.</li>
	<li>A <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/json/JSONObject.html"
class="external-link" rel="nofollow">JSONObject</a> or <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/json/JSONArray.html"
class="external-link" rel="nofollow">JSONArray</a>, which will be sent as the response.</li>
	<li>A <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html"
class="external-link" rel="nofollow">StreamResponse</a>, which will be sent as the
response.</li>
</ul>

    </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+and+Zones">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=25202583&revisedVersion=14&originalVersion=13">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message