Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Lots of rewording, trying to simplify and organize this material for new users. Not done yet, though.

Component Events

Component events are the means by which components are made aware of behaviors by the userTapestry's way of conveying a user's interactions with the web page, such as clicking links and submitting forms.

Component events are used for two purposes:

  • They represent requests initiated by the user, triggered by links and forms in the client web browser. These are described more fully in page navigation and in request processing.
  • They represent flow-of-control within a request, allowing one component to notify its container about some kind of circumstance ("a form was submitted"), or to collect some piece for data from the container.
    Often, a navigation request (originating with the user) will spawn a number of flow-of-control requests. For example, a Form component will be triggered by an action request, and will then send notification events to announce when the form submission is about to be processed, and whether it was succesful or not.

In Tapestry 4, you would configure a parameter of a component with the name of a method to invoke when a certain event occured, usually a request from the client.

This has some limitations, including the fact that only a single method could be invoked, and that it tied together a component and a method based on a method name, which required careful coordination between the template and the Java code.

Tapestry 5 introduces the concept of event handler methods, identified via a naming convention, or via the OnEvent annotation. Event handler methods may have any visibility, even private. Normally they are given package private visibility, to support testing.

Rather than configure a component to invoke a particular method, you identify one or more methods to listen for events from that component. A single event handler method may receive notifications from many different components.

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

Let's review a simple example. Here's a portion of the template for For example, here's a portion of a page (let's call it "Chooser") that lets the user choose a number between 1 and 10:

Code Block
xml
xml
<p> Choose a number from 1 to 10: </p>

<p>
    <t:count end="10" value="index">
        <a t:id="select" t:type="actionlink" context="index">${index}</t:comp>
    </t:count>
</p>

The Notice that Chooser.tml contains an ActionLink component. When rendered on the page, the ActionLink component creates an action URL, which in this case might look like http://localhost:8080/chooser.select/3Image Added

The 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 (s).

A sample URL: http://localhost:8080/chooser.select/3Image Removed.

When there are additional context values, they "3"). Additional context values, if any, are appended to the path.

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.

This demonstrates a critical difference between Tapestry and a more traditional, action oriented framework. This The URL doesn't say what happens when the link is clicked, it identifies which component is responsible when the link is clicked.

There's no simple mapping from URL to a piece of code; instead the component sends notifications, in the form of invocations of event handler methods, and Tapestry ensures that the correct bit of code, code that you supply, gets invoked.

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.

Event Handler Methods

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 @OnEvent annotation.A Java method can be invoked when the link for the component is clicked by the user:

Code Block
java
java
  @OnEvent(component = "select")
  void valueChosen(int value)
  {
    this.value = value;
  }

Tapestry has done does two things here:

  • It has identified Because of the annotation, it identifies method valueChosen() as the method to invoke.
  • It has converted When the link is clicked, it converts the context value from a string to an integer and passed passes it into the method.

In the above example, the valueChosen() method will be invoked

...

when the default event, "action",

...

occurs in the select component

...

(and has at least one context value).

Some For some components can emit , more than one type of event can occur, in which case you will want to be more specific:

Code Block
java
java
  @OnEvent(value = "action", component = "select")
  void valueChosen(int value)
  {
    this.value = value;
  }

The value attribute of the OnEvent annotation is the name of the event to match. The default event type is "action" is the name of the default event type; the ActionLink and Form components each use this event type.

If you omit the component part of the OnEvent annotation, then you'll recieve receive notifications from all contained components, possibly including nested components (due to event bubbling).As elsewhere, the comparison of event type and component id is caseless.

Tip

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 any component.

Event

...

handler methods are normally given package-private visibility, to support testing, although technically they may have any visibility (even private).

A single event handler method may receive notifications from many different components.

As elsewhere, the comparison of event type and component id is case-insensitive.

Method Naming Convention

As an alternative to the use of annotations, you may name your events in a specific fashionevent handling methods following a certain convention, and Tapestry will find and invoke your methods just as if they were annotated.

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 Action event is emitted by the select component.

The previous example may be rewritten as:

...

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.

...

Method Return Values

Main Article: Page Navigation

For page navigation events (originating in components such as ActionLink and Form), the value returned from an event handler method determines how Tapestry will render a response.

If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.

If the name of a page, or a page class or page instance, is returned, then a render request URL will be constructed and sent to the client as a redirect to that page.

See Page Navigation for other options.

Multiple Method Matches

In some cases, you there may have be multiple event handler methods match matching a single event. The order is as followsIn that case, Tapestry invokes them in the following order:

  • Base class methods before sub-class methods.
  • Matching methods within a class in alphabetical order.
  • For a single method name with multiple overrides, by number of parameters, descending. There's only rare cases where it makes sense for

Of course, ordinarily would you not want to create more than one method to handle an event.

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 implementation of the base class method via an override, but can't change the timing of when that method is invoked. See TAPESTRYissue TAP5-231151.

Event Context

The context values (the context parameter to the 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".)

Again, whatever your value is (string, number, date), it is converted into a plain string. This results in a more readable URL.

...

Your event handler method may even declare that it "throws Exception" if that is more convienientconvenient.

Intercepting Event Exceptions

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.

Tapestry fires emits a new event, of type "exception", passing the thrown exception as the context. In fact, the exception is wrapped inside a ComponentEventException, from which you may extract the event type and context.

...

The return value of the exception event handler replaces 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 navigational response such as a page instance or page name.

This can be handy for handling cases where the data in the URL is misformattedincorrectly formatted.

In the above example, the navigational response is the page itself.

If there is no exception event handler, or the exception event handler returns null (or is void), then then the exception will be passed to the RequestExceptionHandler service, which (in default configuratonconfiguration) will be render the exception page.