You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

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't have to write any JavaScript code.

Zones

Zones are Tapestry's approach to performing partial page updates. A Zone component renders as an HTML element, typically a <div>, 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.)

A Zone can be updated via an EventLink or ActionLink component, or by a Form. All of these components support a zone parameter, which provides the id of the Zone's <div>. 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's <div> in place.

An Update div within a Zone div

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 <div> may contain an update <div>.

An Update <div> is specifically a <div> element marked with the CSS class "t-zone-update", inside the Zone's <div>.

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

The show and update functions apply to the Zone <div>.

Event Handler Return Types

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

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

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

Alternatively, an event handler may return a Link 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.

Multiple Zone Updates

An event handler may cause multiple zones to be updated on the client side. To accomplish this, return a MultiZoneUpdate 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).

The renderer for each zone can be a block or component, or a Renderable or RenderCommand ... 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:

  @Inject
  private Form registrationForm;

  @Inject Block registrationHelp;

  Object onActionFromRegister()
  {
    return new MultiZoneUpdate("userInput", registrationForm).add("helpPanel", registrationHelp);
  }

This implies that there are two zones, "userInput" and "helpPanel", somewhere in the rendered page, waiting to receive the updated content.

Graceful Degradation

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 traditional request.

To support graceful degradation, you should detect that case and return a traditional response: a page, page name or page class.

This is accomplished by injecting the Request object, and invoking the isXHR() method. This value will be true for Ajax requests, and false for traditional request.

Zone Functions

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. The Zone's show parameter is the name of a Tapestry.ElementEffect function.

If a Zone is already visible, then a different function is used to highlight the change. Here it is the Zone's update parameter, and a default highlight() function, which performs a yellow fade to highlight that the content of the Zone has changed.

Zone Limitations

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 uniqueify the client id you specify (appending an index number).

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.

Coming Soon

  • Extending a Form with a Zone
  • Additional Tapestry.ElementEffect functions, plus documentation
  • Real examples ...

Autocomplete Mixin

The Autocomplete 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.

Autocomplete can be added to an existing text field:

  <t:textfield t:id="accountName" t:mixins="autocomplete" size="100"/>

The mixin can be configured in a number of ways, see the component reference.

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

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.

For example:

  List<String> onProvideCompletionsFromAccountName(String partial)
  {
    List<Account> matches = accountDAO.findByPartialAccountName(partial);

    List<String> result = new ArrayList<String>():

    for (Account a : matches)
    {
      result.add(a.getName());
    }

    return result;
  }

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

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

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

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

Your own Ajax Components

A study of the Autocomplete mixin's source code should be very helpful: it shows how to ask the ComponentResources object to create a link.

The key part is the way Tapestry invokes a component event handler method on the component.

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.

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

The possible return values are:

  • 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.
  • A JSONObject or JSONArray, which will be sent as the response.
  • A StreamResponse, which will be sent as the response.
  • No labels