Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Component events 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 occursis triggered, 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 a page (let's call it "ChooserReview") that lists documents and lets the user choose a number between 1 and 10:a user click to edit any one of them.

Code Block
languagexml
titleChooserReview.tml (partial)
<p> Choose a number from 1Select document to 10:

    <t:count end="10edit: </p>
<t:loop source="documents" value="indexdocument">
    <div>
    <a t:id="select"   <t:actionlink" t:typeid="actionlinkedit" context="index">${index}</a>document.id"> ${document.name} </t:actionlink>       
    </t:count>div>
</p>t:loop>

Notice that ChooserReview.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:

    http://localhost:8080/chooserreview.selectedit/3

This URL identifies the page that contains the component ("chooserreview"), the type of event (unless it is "action", the default and most common event type), the the Component id of the component within the page ("selectedit"), plus and the additional context value ("3", the "id" property of the document). Additional context values, if any, are appended to the path. (The URL may also contain the event name, unless, as here, it is "action".)

There's no direct mapping from URL to a piece of code. Instead, when the user clicks on the link, the ActionLink component emits triggers events. And then Tapestry ensures that the correct bit bits of code (your event handler method, see below) gets get invoked for those events.

...

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 will trigger a form component, which will then emit 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.

...

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.

Code Block
languagejava
  @OnEvent(component = "selectedit")
  void valueChoseneditDocument(int valuedocId)
  {
    this.valueselectedId = valuedocId;
    // do something with the document here
}

Tapestry does two things here:

  • Because of the annotation, it identifies method valueChoseneditDocument() as the method to invoke .whenever the component whose ID is "edit" ActionLink component triggers an event.
  • Because there is a method parameter, when the When the link is clicked , it converts the context value of the request is converted from a string to an integer and passes it into passed in as the method's value parameter.

Since
since5.3
Starting in release 5.3, Tapestry will validate that throw an exception if the component , if any, identified for the event handler method actually exists doesn't exist in the containing component's template. This helps with typos in annotations (or in the naming conventions identified below). prevent typos.

In the above example, the valueChoseneditDocument() method will be invoked when the default event, "action", any event occurs in in the select "edit" component (and has at least one context value).

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

Code Block
languagejava
  @OnEvent(value = "action", component = "selectedit")
  void valueChoseneditDocument(int valuedocId)
  {
    this.valueselectedId = valuedocId;
     }
// do something with the document here
}

For the OnEvent For the OnEvent annotation, the value attribute identifies the name of the event to match. We specified "action" because the ActionLink component emits triggers the "action" event, as noted in the Component Events section of its javadocs.

...

Code Block
languagexml
titleAn EventLink that emits the "clear" event
<t:eventlink event="cleardelete" context="index">${index}<document.id">document.name</a>

which is equivalent to:

Code Block
languagexml
titleAn EventLink that emits the "clear" event
<a t:type="eventlink" t:id="cleardelete" context="index">${index}<document.id">document.name</a>

Note that if you omit the component part of the OnEvent annotation, then you'll receive notifications from all contained components, possibly including nested components (due to event bubbling).

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 ID means that the method will be invoked for events from any component.

...

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

Method Naming Convention

...

This style of event handler methods start with the prefix "on", followed by the name of the actionevent. You may then continue by adding "From" and a capitalized component id (remember that Tapestry is case insensitive about event names and component idsIDs). So, for example, a method named onActionFromSelect(), if it exists, is invoked whenever an Action event is emitted triggered by the select component.

The previous example may be rewritten as:

Code Block
languagejava
  void onActionFromSelectonActionFromEdit(int valuedocId)
  {
    this.valueselectedId = valuedocId;
    // do something with the document here
}
Info

Note from Howard: I've found that I Many people prefer the naming convention approach, and reserve the annotation just for situations that don't otherwise fit.

...

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

In some many cases , it is desirable 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:

...

context values). The context values may be passed to an event handler method as parameter of the following types:

Code Block
Object onActionFromEdit(EventContext context)
{
    if (context.getCount() > 0) {
        this.selectedId = context.get(0);
        // do something with the document here
    } else {
        alertManager.warn("Please select a document.");
        return null;
    }
}

 

...

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 all context values.

...

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

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 triggered by those nested components (see Triggering Events, below), and use that custom event name in your event handler method.

...

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.

Wiki Markup
{float:right|background=#eee|padding=0 1em}
    *JumpStart Demo:*
    [Handling A Bad Context|http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1]
{float}
Tapestry emits triggers 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.

...

For example, the following emits triggers an "updateAll" event. A containing component can then respond to it, if desired, with an "onUpdateAll()" method in its own component class.

...