tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From build...@apache.org
Subject svn commit: r987749 - in /websites/production/tapestry/content: cache/main.pageCache component-events.html
Date Sun, 08 May 2016 20:19:32 GMT
Author: buildbot
Date: Sun May  8 20:19:32 2016
New Revision: 987749

Log:
Production update by buildbot for tapestry

Modified:
    websites/production/tapestry/content/cache/main.pageCache
    websites/production/tapestry/content/component-events.html

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

Modified: websites/production/tapestry/content/component-events.html
==============================================================================
--- websites/production/tapestry/content/component-events.html (original)
+++ websites/production/tapestry/content/component-events.html Sun May  8 20:19:32 2016
@@ -69,7 +69,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p><strong>Component events</strong>
are Tapestry's way of conveying a user's interactions with the web page, such as clicking
links and submitting forms, to designated methods in your page and component classes. When
a component event occurs, Tapestry calls the event handler method you've provided, if any,
in the containing component's class.</p><div class="aui-label" style="float:right"
title="Related Articles">
+                <div id="ConfluenceContent"><p><strong>Component events</strong>
are Tapestry's way of conveying a user's interactions with the web page, such as clicking
links and submitting forms, to designated methods in your page and component classes. When
a component event is triggered, Tapestry calls the event handler method you've provided, if
any, in the containing component's class.</p><div class="aui-label" style="float:right"
title="Related Articles">
 
 
 
@@ -135,45 +135,59 @@
                         
                     </div>
     </li></ul>
-</div><p>Let's review a simple example. Here's a portion of the template for
a page (let's call it "Chooser") that lets the user choose a number between 1 and 10:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader
pdl" style="border-bottom-width: 1px;"><b>Chooser.tml (partial)</b></div><div
class="codeContent panelContent pdl">
-<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;p&gt;
Choose a number from 1 to 10:
-
-    &lt;t:count end="10" value="index"&gt;
-        &lt;a t:id="select" t:type="actionlink" context="index"&gt;${index}&lt;/a&gt;
-    &lt;/t:count&gt;
-&lt;/p&gt;
-</pre>
-</div></div><p>Notice that Chooser.tml contains an ActionLink component.
When rendered on the page, the ActionLink component creates a component event request URL,
with the event type set to "action". In this case the URL might look like <code><a
 class="external-link" href="http://localhost:8080/chooser.select/3" rel="nofollow">http://localhost:8080/chooser.select/3</a></code></p><p>This
URL identifies the page that contains the component ("chooser"), the type of event (unless
it is "action", the default and most common event type), the id of the component within the
page ("select"), plus the additional context value ("3"). <em>Additional context values,
if any, are appended to the path.</em></p><p>There's no direct mapping from
URL to a piece of code. Instead, when the user clicks on the link, the ActionLink component
emits events. And then Tapestry ensures that the correct bit of code (your event handler method,
see below) gets invoked for those events.</p><p>This demonstrates a 
 critical difference between Tapestry and a more traditional, action oriented framework. The
URL doesn't say what happens when the link is clicked, it identifies <em>which component
is responsible</em> when the link is clicked.</p><p>Often, a navigation
request (originating with the user) will spawn a number of flow-of-control requests. For example,
an action event will trigger a form component, which will then emit notification events to
announce when the form submission is about to be processed, and whether it was successful
or not, and those event could be further handled by the page component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event
Handler Methods</h1><p>When a component event occurs, Tapestry invokes any event
handler methods that you have identified for that event. You can identify your event handler
methods via a naming convention (see Method Naming Convention below), or via the @<a  class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apac
 he/tapestry5/annotations/OnEvent.html">OnEvent</a> annotation.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent
pdl">
-<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  @OnEvent(component
= "select")
-  void valueChosen(int value)
-  {
-    this.value = value;
-  }
+</div><p>Let's look at a simple example. Here's a portion of the template for
a page (let's call it "Review") that lists documents and lets a user click to edit any one
of them.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width: 1px;"><b>Review.tml (partial)</b></div><div
class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;p&gt;
Select document to edit: &lt;/p&gt;
+&lt;t:loop source="documents" value="document"&gt;
+    &lt;div&gt;
+        &lt;t:actionlink" t:id="edit" context="document.id"&gt; ${document.name}
&lt;/t:actionlink&gt;       
+    &lt;/div&gt;
+&lt;/t:loop&gt;
+</pre>
+</div></div><p>Notice that Review.tml contains an ActionLink component
in a loop. When rendered on the page, the ActionLink component creates a component event request
URL, with the event type set to "action". In this case the URL might look like:</p><p><code><span
class="external-link">&#160;&#160;&#160; http://localhost:8080/review.edit/3</span></code></p><p>This
URL identifies the <strong>page</strong> that contains the component ("review"),
the&#160;<strong>Component id</strong> of the component within the page ("edit"),
and the <strong>context</strong> value ("3", the "id" property of the document).
<em>Additional context values, if any, are appended to the path.</em> (The URL
may also contain the <strong>event name</strong>, unless, as here, it is "action".)</p><p>There's
no direct mapping from URL to a piece of code. Instead, when the user clicks on the link,
the ActionLink component triggers events. And then Tapestry ensures that the correct bits
of code (your event handler 
 method, see below) get invoked for those events.</p><p>This demonstrates a critical
difference between Tapestry and a more traditional, action oriented framework. The URL doesn't
say what happens when the link is clicked, it identifies <em>which component is responsible</em>
when the link is clicked.</p><p>Often, a navigation request (originating with
the user) will spawn a number of flow-of-control requests. For example, a form component may
trigger an action event, which will then trigger notification events to announce when the
form submission is about to be processed, and whether it was successful or not, and those
event could be further handled by the page component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event
Handler Methods</h1><p>When a component event occurs, Tapestry invokes any event
handler methods that you have identified for that event. You can identify your event handler
methods via a naming convention (see Method Naming Convention below), or via the @<a  cl
 ass="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a>
annotation.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@OnEvent(component="edit")
+void editDocument(int docId)
+{
+    this.selectedId = docId;
+    // do something with the document here
+}
 </pre>
-</div></div><p>Tapestry does two things here:</p><ul><li>Because
of the annotation, it identifies method valueChosen() as the method to invoke.</li><li>When
the link is clicked, it converts the context value from a string to an integer and passes
it into the method.</li></ul>
+</div></div><p>Tapestry does two things here:</p><ul><li>Because
of the annotation, it identifies method editDocument() as the method to invoke whenever the
component whose ID is "edit" ActionLink component triggers an event.</li><li>Because
there is a method parameter, when the link is clicked the context value of the request is
converted from a string to an integer and passed in as the method's value parameter.<br
clear="none"><br clear="none"></li></ul>
 
 <div class="confluence-information-macro confluence-information-macro-information"><p
class="title">Added in 5.3</p><span class="aui-icon aui-icon-small aui-iconfont-info
confluence-information-macro-icon"></span><div class="confluence-information-macro-body">
 </div></div>
 <div style="border-right: 20px solid #D8E4F1;border-left: 20px solid #D8E4F1;">
-<p>Starting in release 5.3, Tapestry will validate that the component, if any, identified
for the event handler method actually exists in the containing component's template. This
helps with typos in annotations (or in the naming conventions identified below).</p>
-</div><p>In the above example, the valueChosen() method will be invoked when
the default event, "action", occurs in the <code>select</code> component (and
has at least one context value).</p><p>For some components, more than one type
of event can occur, in which case you will want to be more specific:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  @OnEvent(value
= "action", component = "select")
-  void valueChosen(int value)
-  {
-    this.value = value;
-  }
-</pre>
-</div></div><p>For the OnEvent annotation, the <em><code>value</code></em>
attribute identifies the name of the event to match. We specified "action" because the ActionLink
component emits the "action" event, as noted in the Component Events section of its <a
 class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">javadocs</a>.</p><p>Alternatively,
we can use the EventLink component, in which case the name of the event is determined by us
&#8211; either through the "event" parameter or the element's ID:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>An EventLink that emits the "clear" event</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;t:eventlink
event="clear" context="index"&gt;${index}&lt;/a&gt;</pre>
-</div></div><p>which is equivalent to:</p><div class="code panel
pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>An EventLink that emits the "clear" event</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;a
t:type="eventlink" t:id="clear" context="index"&gt;${index}&lt;/a&gt;</pre>
-</div></div><p>Note that if you omit the <code>component</code>
part of the OnEvent annotation, then you'll receive notifications from <em>all</em>
contained components, possibly including nested components (due to event bubbling).</p><div
class="confluence-information-macro confluence-information-macro-tip"><span class="aui-icon
aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>You should usually specify exactly which
component(s) you wish to receive events from. Using @OnEvent on a method and not specifying
a specific component id means that the method will be invoked for events from <em>any</em>
component.</p></div></div><p>To support testing, it's a common practice
to give event handler methods <em>package-private</em> visibility, as in the examples
on this page, although technically they may have any visibility (even private).</p><p>A
single event handler method may receive notifications from many dif
 ferent components.</p><p>As elsewhere, the comparison of event type and component
id is case-insensitive.</p><h2 id="ComponentEvents-MethodNamingConvention">Method
Naming Convention</h2><p>As an alternative to the use of annotations, you may
name your event handling methods following a certain convention, and Tapestry will find and
invoke your methods just as if they were annotated.</p><p>This style of event
handler methods start with the prefix "on", followed by the name of the action. You may then
continue by adding "From" and a capitalized component id (remember that Tapestry is case insensitive
about event names and component ids). So, for example, a method named onActionFromSelect(),
if it exists, is invoked whenever an <code>Action</code> event is emitted by the
<code>select</code> component.</p><p>The previous example may be rewritten
as:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  void
onActionFromSelect(int value)
-  {
-    this.value = value;
-  }
-</pre>
-</div></div><div class="confluence-information-macro confluence-information-macro-information"><span
class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Note from Howard: I've found that I
prefer the naming convention approach, and reserve the annotation just for situations that
don't otherwise fit.</p></div></div><h2 id="ComponentEvents-MethodReturnValues">Method
Return Values</h2><p>Main Article: <a  href="page-navigation.html">Page
Navigation</a></p><p>For page navigation events (originating in components
such as EventLink, ActionLink and Form), the value returned from an event handler method determines
how Tapestry will render a response.</p><ul><li><strong>Null</strong>:
For no value, or null, the current page (the page containing the component) will render the
response.</li><li><strong>Page</strong>: For the name of a page, or
a page class or page instance, a render request URL will be con
 structed and sent to the client as a redirect to that page.</li><li><strong>URL</strong>:
For a java.net.URL, a redirect will be sent to the client. (In Tapestry 5.3.x and earlier,
this only works for non-Ajax requests.)</li><li><strong>Zone body</strong>:
In the case of an Ajax request to update a zone, the component event handler will return the
new zone body, typically via an injected component or block.</li><li><strong>HttpError</strong>:
For an <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>,
an error response is sent to the client.</li><li><strong>Link</strong>:
For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>,
a redirect is sent to the client.</li><li><strong>Stream</strong>:
For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a>,
a 
 stream of data is sent to the client</li><li><strong>boolean:</strong>
<em>true</em> prevents the event from bubbling up further; <em>false</em>
lets it bubble up. See Event Bubbling, below.</li></ul><p>See <a  href="page-navigation.html">Page
Navigation</a> for more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple
Method Matches</h2><p>In some cases, there may be multiple event handler methods
matching a single event. In that case, Tapestry invokes them in the following order:</p><ul><li>Base
class methods before sub-class methods.</li><li>Matching methods within a class
in alphabetical order.</li><li>For a single method name with multiple overrides,
by number of parameters, descending.</li></ul><p>Of course, ordinarily would
you <em>not</em> want to create more than one method to handle an event.</p><p>When
a sub-class overrides an event handler method of a base class, the event handler method is
only invoked once, along with any other base class methods. The su
 bclass can change the <em>implementation</em> of the base class method via an
override, but can't change the <em>timing</em> of when that method is invoked.
See <a  class="external-link" href="https://issues.apache.org/jira/browse/TAP5-51">issue
TAP5-51</a>.</p><h2 id="ComponentEvents-EventContext">Event Context</h2><p>The
context values (the context parameter to the EventLink or ActionLink component) can be any
object. However, only a simple conversion to string occurs. (This is in contrast to Tapestry
4, which had an elaborate type mechanism with the odd name "DataSqueezer".)</p><p>Again,
whatever your value is (string, number, date), it is converted into a plain string. This results
in a more readable URL.</p><p>If you have multiple context values (by binding
a list or array of objects to the <em>context</em> parameter of the EventLink
or ActionLink), then each one, in order, will be added to the URL.</p><p>When
an event handler method is invoked, the strings are converted back i
 nto values, or even objects. A <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
is used to convert between client-side strings and server-side objects. The <a  class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a>
service provides the necessary value encoders.</p><p>As shown in the example above,
most of the parameters passed to the event handler method are derived from the values provided
in the event context. Each successive method parameter matches against a value provided in
the event context (the context parameter of the ActionLink component; though many components
have a similar context parameter).</p><p>In some cases, it is desirable to have
direct access to the context (for example, to adapt to cases where there are a variable number
of context values). The context values may be passed to an event ha
 ndler method as parameter of the following types:</p><ul><li><a  class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List&lt;Object&gt;</li></ul><p>The
latter two should be avoided, they may be removed in a future release. In all of these cases,
the context parameter acts as a freebie; it doesn't match against a context value as it represents
<em>all</em> context values.</p><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing
Request Query Parameters</h2><p>A parameter may be annotated with the @RequestParameter
annotation; this allows query parameters (?name1=value1&amp;name2=value2, etc) to be extracted
from the request, converted to the correct type, and passed to the method. Again, this doesn't
count against the event context values.</p><h2 id="ComponentEvents-MethodMatching">Method
Matching</h2><p>An event handler method will only be invoked <em>if the
context cont
 ains at least as many values as the method has parameters</em>. Methods with too many
parameters will be silently skipped.</p><p>Tapestry will silently skip over a
method if there are insufficient values in the context to satisfy the number of parameters
requested.</p><p>EventContext parameters, and parameters annotated with @RequestParameter,
do not count against this limit.</p><h2 id="ComponentEvents-MethodOrdering">Method
Ordering</h2><p>When multiple methods match within the same class, Tapestry will
invoke them in ascending alphabetical order. When there are multiple overrides of the same
method name, Tapestry invokes them in descending order by number of parameters. In general,
these situations don't happen ... in most cases, only a single method is required to handle
a specific event form a specific component.</p><p>An event handler method may
return the value <code>true</code> to indicate that the event has been handled;
this immediately stops the search for additional metho
 ds in the same class (or in base classes) or in containing components.</p><h1 id="ComponentEvents-EventBubbling">Event
Bubbling</h1><p>The event will bubble up the component hierarchy, first to the
containing component, then <em>that</em> component's containing component or page,
and so on, until it is <em>aborted</em> by an event handler method returning <em>true</em>
or a non-null value.</p><p>Returning a boolean value from an event handler method
is special. Returning <em>true</em> will abort the event with no result; use this
when the event is fully handled without a return value and no further event handlers (in the
same component, or in containing components) should be invoked.</p><p>Returning
<em>false</em> is the same as returning null; event processing will continue to
look for more event handlers, in the same component or its parent.</p><p>When
an event bubbles up from a component to its container, the origin of the event is changed
to be the component. For example, a Form
  component inside a BeanEditForm component may fire a success event. The page containing
the BeanEditForm may listen for that event, but it will be from the BeanEditForm component
(which makes sense, because the id of the Form inside the BeanEditForm is part of the BeanEditForm's
implementation, not its public interface).</p><p>If you want to handle events
that have bubbled up from nested component, you'll soon find that you don't have easy access
to the component ID of the firing component. In practical terms this means that you'll want
to trigger custom events for the events emitted by those nested components (see Triggering
Events, below), and use that custom event name in your event handler method.</p><h1
id="ComponentEvents-EventMethodExceptions">Event Method Exceptions</h1><p>Event
methods are allowed to throw any exception (not just runtime exceptions). If an event method
does throw an exception, Tapestry will catch the thrown exception and ultimately display the
exception re
 port page.</p><p>In other words, there's no need to do this:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent
pdl">
+<p>Starting in release 5.3, Tapestry will throw an exception if the component identified
for the event handler method doesn't exist in the containing component's template. This helps
prevent typos.</p>
+</div><p>In the above example, the editDocument() method will be invoked when
any event occurs in in the "edit" component (and has at least one context value).</p><p>For
some components, more than one type of event can occur, in which case you will want to be
more specific:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@OnEvent(value="action",
component="edit")
+void editDocument(int docId)
+{
+    this.selectedId = docId;
+    // do something with the document here
+}
+</pre>
+</div></div><p>For the OnEvent annotation, the <em><code>value</code></em>
attribute identifies the name of the event to match. We specified "action" because the ActionLink
component triggers the "action" event, as noted in the Component Events section of its <a
 class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">javadocs</a>.</p><p>Alternatively,
we can use the EventLink component, in which case the name of the event is determined by us
&#8211; either through the "event" parameter or the element's ID:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>An EventLink that emits the "delete" event</b></div><div
class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;t:eventlink
event="delete" context="document.id"&gt; ${document.name} &lt;/t:eventlink&gt;</pre>
+</div></div><p>which is equivalent to:</p><div class="code panel
pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>An EventLink that emits the "delete" event</b></div><div
class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;a
t:type="eventlink" t:id="delete" context="document.id"&gt; ${document.name} &lt;/a&gt;</pre>
+</div></div><p>Note that if you omit the <code>component</code>
part of the OnEvent annotation, then you'll receive notifications from <em>all</em>
contained components, possibly including nested components (due to event bubbling).</p><div
class="confluence-information-macro confluence-information-macro-tip"><span class="aui-icon
aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>You should usually specify exactly which
component(s) you wish to receive events from. Using @OnEvent on a method and not specifying
a specific component ID means that the method will be invoked for events from <em>any</em>
component.</p></div></div><p>To support testing, it's a common practice
to give event handler methods <em>package-private</em> visibility, as in the examples
on this page, although technically they may have any visibility (even private).</p><p>A
single event handler method may receive notifications from many dif
 ferent components.</p><p>As elsewhere, the comparison of event type and component
ID is case-insensitive.</p><h2 id="ComponentEvents-MethodNamingConvention">Method
Naming Convention</h2><p>As an alternative to the use of annotations, you may
name your event handling methods following a certain convention, and Tapestry will find and
invoke your methods just as if they were annotated.</p><p>This style of event
handler methods start with the prefix "on", followed by the name of the event. You may then
continue by adding "From" and a capitalized component id (remember that Tapestry is case insensitive
about event names and component IDs). So, for example, a method named onValidateFromSave()
will be invoked whenever a "Validate" event is triggered by a component whose component ID
is "save".</p><p>The previous example may be rewritten as:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">void
onActionFromEdit(int docId)
+{
+    this.selectedId = docId;
+    // do something with the document here
+}
+</pre>
+</div></div><div class="confluence-information-macro confluence-information-macro-information"><span
class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Many people prefer the naming convention
approach, reserving the annotation just for situations that don't otherwise fit.</p></div></div><h2
id="ComponentEvents-MethodReturnValues">Method Return Values</h2><p>Main Article:
<a  href="page-navigation.html">Page Navigation</a></p><p>For page
navigation events (originating in components such as EventLink, ActionLink and Form), the
value returned from an event handler method determines how Tapestry will render a response.</p><ul><li><strong>Null</strong>:
For no value, or null, the current page (the page containing the component) will render the
response.</li><li><strong>Page</strong>: For the name of a page, or
a page class or page instance, a render request URL will be constructed and sent to the c
 lient as a redirect to that page.</li><li><strong>URL</strong>: For
a java.net.URL, a redirect will be sent to the client. (In Tapestry 5.3.x and earlier, this
only works for non-Ajax requests.)</li><li><strong>Zone body</strong>:
In the case of an Ajax request to update a zone, the component event handler will return the
new zone body, typically via an injected component or block.</li><li><strong>HttpError</strong>:
For an <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>,
an error response is sent to the client.</li><li><strong>Link</strong>:
For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>,
a redirect is sent to the client.</li><li><strong>Stream</strong>:
For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a>,
a stream of data is sent to 
 the client</li><li><strong>boolean:</strong> <em>true</em>
prevents the event from bubbling up further; <em>false</em> lets it bubble up.
See Event Bubbling, below.</li></ul><p>See <a  href="page-navigation.html">Page
Navigation</a> for more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple
Method Matches</h2><p>In some cases, there may be multiple event handler methods
matching a single event. In that case, Tapestry invokes them in the following order:</p><ul><li>Base
class methods before sub-class methods.</li><li>Matching methods within a class
in alphabetical order.</li><li>For a single method name with multiple overrides,
by number of parameters, descending.</li></ul><p>Of course, ordinarily would
you <em>not</em> want to create more than one method to handle an event.</p><p>When
a sub-class overrides an event handler method of a base class, the event handler method is
only invoked once, along with any other base class methods. The subclass can change the <em>
 implementation</em> of the base class method via an override, but can't change the
<em>timing</em> of when that method is invoked. See <a  class="external-link"
href="https://issues.apache.org/jira/browse/TAP5-51">issue TAP5-51</a>.</p><h2
id="ComponentEvents-EventContext">Event Context</h2><p>The context values (the
context parameter to the EventLink or ActionLink component) can be any object. However, only
a simple conversion to string occurs. (This is in contrast to Tapestry 4, which had an elaborate
type mechanism with the odd name "DataSqueezer".)</p><p>Again, whatever your value
is (string, number, date), it is converted into a plain string. This results in a more readable
URL.</p><p>If you have multiple context values (by binding a list or array of
objects to the <em>context</em> parameter of the EventLink or ActionLink), then
each one, in order, will be added to the URL.</p><p>When an event handler method
is invoked, the strings are converted back into values, or even object
 s. A <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
is used to convert between client-side strings and server-side objects. The <a  class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a>
service provides the necessary value encoders.</p><p>As shown in the example above,
most of the parameters passed to the event handler method are derived from the values provided
in the event context. Each successive method parameter matches against a value provided in
the event context (the context parameter of the ActionLink component; though many components
have a similar context parameter).</p><p>In many cases it is helpful to have direct
access to the context (for example, to adapt to cases where there are a variable number of
context values). The context values may be passed to an event handler method as parameter
of 
 the following types:</p><ul><li><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List&lt;Object&gt;</li></ul><p>The
latter two should be avoided, they may be removed in a future release. In all of these cases,
the context parameter acts as a freebie; it doesn't match against a context value as it represents
<em>all</em> context values.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">Object
onActionFromEdit(EventContext context)
+{
+    if (context.getCount() &gt; 0) {
+        this.selectedId = context.get(0);
+        // do something with the document here
+    } else {
+        alertManager.warn("Please select a document.");
+        return null;
+    }
+}</pre>
+</div></div><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing
Request Query Parameters</h2><p>A parameter may be annotated with the @RequestParameter
annotation; this allows query parameters (?name1=value1&amp;name2=value2, etc) to be extracted
from the request, converted to the correct type, and passed to the method. Again, this doesn't
count against the event context values.</p><p>See the example in the <a  href="link-components-faq.html">Link
Components FAQ</a>.</p><h2 id="ComponentEvents-MethodMatching">Method Matching</h2><p>An
event handler method will only be invoked <em>if the context contains at least as many
values as the method has parameters</em>. Methods with too many parameters will be silently
skipped.</p><p>Tapestry will silently skip over a method if there are insufficient
values in the context to satisfy the number of parameters requested.</p><p>EventContext
parameters, and parameters annotated with @RequestParameter, do not count against this limi
 t.</p><h2 id="ComponentEvents-MethodOrdering">Method Ordering</h2><p>When
multiple methods match within the same class, Tapestry will invoke them in ascending alphabetical
order. When there are multiple overrides of the same method name, Tapestry invokes them in
descending order by number of parameters. In general, these situations don't happen ... in
most cases, only a single method is required to handle a specific event form a specific component.</p><p>An
event handler method may return the value <code>true</code> to indicate that the
event has been handled; this immediately stops the search for additional methods in the same
class (or in base classes) or in containing components.</p><h1 id="ComponentEvents-EventBubbling">Event
Bubbling</h1><p>The event will bubble up the component hierarchy, first to the
containing component, then <em>that</em> component's containing component or page,
and so on, until it is <em>aborted</em> by an event handler method returning <em>true</em>
or a
  non-null value.</p><p>Returning a boolean value from an event handler method
is special. Returning <em>true</em> will abort the event with no result; use this
when the event is fully handled without a return value and no further event handlers (in the
same component, or in containing components) should be invoked.</p><p>Returning
<em>false</em> is the same as returning null; event processing will continue to
look for more event handlers, in the same component or its parent.</p><p>When
an event bubbles up from a component to its container, the origin of the event is changed
to be the component. For example, a Form component inside a BeanEditForm component may trigger
a success event. The page containing the BeanEditForm may listen for that event, but it will
be from the BeanEditForm component (which makes sense, because the id of the Form inside the
BeanEditForm is part of the BeanEditForm's implementation, not its public interface).</p><p>If
you want to handle events that have bubb
 led up from nested component, you'll soon find that you don't have easy access to the component
ID of the firing component. In practical terms this means that you'll want to trigger custom
events for the events triggered by those nested components (see Triggering Events, below),
and use that custom event name in your event handler method.</p><h1 id="ComponentEvents-EventMethodExceptions">Event
Method Exceptions</h1><p>Event methods are allowed to throw any exception (not
just runtime exceptions). If an event method does throw an exception, Tapestry will catch
the thrown exception and ultimately display the exception report page.</p><p>In
other words, there's no need to do this:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  void
onActionFromRunQuery()
   {
     try
@@ -194,7 +208,7 @@
 </pre>
 </div></div><p>Your event handler method may even declare that it "throws
Exception" if that is more convenient.</p><h1 id="ComponentEvents-InterceptingEventExceptions">Intercepting
Event Exceptions</h1><p>When an event handler method throws an exception (checked
or runtime), Tapestry gives the component and its containing page a chance to handle the exception,
before continuing on to report the exception.</p><div class="navmenu" style="float:right;
background:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong><br clear="none">
-    <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1"
rel="nofollow">Handling A Bad Context</a></p></div>Tapestry emits a new
event, of type "exception", passing the thrown exception as the context. In fact, the exception
is wrapped inside a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/ComponentEventException.html">ComponentEventException</a>,
from which you may extract the event type and context.<p>Thus:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+    <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1"
rel="nofollow">Handling A Bad Context</a></p></div>Tapestry triggers
a new event, of type "exception", passing the thrown exception as the context. In fact, the
exception is wrapped inside a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/ComponentEventException.html">ComponentEventException</a>,
from which you may extract the event type and context.<p>Thus:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  Object
onException(Throwable cause)
   {
     message = cause.getMessage();
@@ -204,7 +218,7 @@
 </pre>
 </div></div><p>The return value of the exception event handler <em>replaces</em>
the return value of original event handler method. For the typical case (an exception thrown
by an "activate" or "action" event), this will be a <a  href="page-navigation.html">navigational
response</a> such as a page instance or page name.</p><p>This can be handy
for handling cases where the data in the URL is incorrectly formatted.</p><p>In
the above example, the navigational response is the page itself.</p><p>If there
is no exception event handler, or the exception event handler returns null (or is void), then
the exception will be passed to the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a>
service, which (in the default configuration) will render the exception page.</p><h1
id="ComponentEvents-TriggeringEvents">Triggering Events</h1><p></p><div
class="navmenu" style="float:right; backg
 round:#eee; margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong><br clear="none">
-    <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/together/ajaxcomponentscrud/persons"
rel="nofollow">AJAX Components CRUD</a></p></div>If you want your own
component to trigger events, just call the <a  rel="nofollow">triggerEvent</a>
method of <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a>
from within the component class.<p>For example, the following emits an "updateAll" event.
A containing component can then respond to it, if desired, with an "onUpdateAll()" method
in its own component class.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Your component
class (partial)</b></div><div class="codeContent panelContent pdl">
+    <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/together/ajaxcomponentscrud/persons"
rel="nofollow">AJAX Components CRUD</a></p></div>If you want your own
component to trigger events, just call the <a  rel="nofollow">triggerEvent</a>
method of <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a>
from within the component class.<p>For example, the following triggers an "updateAll"
event. A containing component can then respond to it, if desired, with an "onUpdateAll()"
method in its own component class.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Your
component class (partial)</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Inject
 ComponentResources componentResources;
 &#160;...




Mime
View raw message