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 Wed, 17 Oct 2012 07:59:00 GMT
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
<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/~demey.emmanuel@gmail.com">DEMEY
                         <h4>Changes (1)</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" >@Inject <br>private Request
request; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
<br>@InjectComponent <br>private Zone zone; <br></td></tr>
            <tr><td class="diff-unchanged" >... <br>Object onClickFromSomeLink()
            <tr><td class="diff-snipped" >...<br></td></tr>
    </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>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/JavaScript">JavaScript</a>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Ajax+and+Zones">Ajax
and Zones</a>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/JavaScript+FAQ">JavaScript
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Component+Cheat+Sheet">Component
Cheat Sheet</a>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Ajax+Components+FAQ">Ajax
Components FAQ</a>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Assets">Assets</a>

<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. But with Tapestry, you don't have to write any JavaScript

<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>.</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>

<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-EventHandlerReturnTypes"></a>Event Handler Return

<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 typically 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>

<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-MultipleZoneUpdates"></a>Multiple Zone Updates</h3>

<p>An event handler may cause multiple zones to be updated on the client side. To accomplish
this, return a <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ajax/MultiZoneUpdate.html"
class="external-link" rel="nofollow">MultiZoneUpdate</a> 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'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>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<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);

<p>This implies that there are two zones, "userInput" and "helpPanel", somewhere in
the rendered page, waiting to receive the updated content.</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">
<span class="code-keyword">private</span> Request request;

<span class="code-keyword">private</span> Zone zone;
<span class="code-object">Object</span> onClickFromSomeLink()
    <span class="code-keyword">if</span>(request.isXHR())
       <span class="code-keyword">return</span> zone.getBody(); <span class="code-comment">//
AJAX request, <span class="code-keyword">return</span> zone body
</span>    }
    <span class="code-keyword">else</span>
       <span class="code-keyword">return</span> <span class="code-keyword">null</span>;
<span class="code-comment">// non-AJAX request, redraw current page
</span>    }

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

<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>

<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; };

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

<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

<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

<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>

<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

<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-FrequentlyAskedQuestions"></a>Frequently Asked

<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>

<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;

<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)

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

<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

<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>

	<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

        <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>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Ajax+and+Zones">View
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=25202583&revisedVersion=13&originalVersion=12">View

View raw message