Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Wiki Markup
{scrollbar}

Ajax Components

Main article: Ajax and Zones

Contents

Table of Contents
excludeContents|Ajax Components
printablefalse

Do I have to specify both id and t:id for Zone components?

The examples for the Zone component (in the Component Reference) consistently specify both id and t:id and this is probably a good idea.

...

The point is, to be sure, specify the exact client id. This will be the value for the zone parameter of the triggering component (such as a Form, PageLink, ActionLink, etc.).

How do I update the content of a Zone from an event handler method?

When a client-side link or form triggers an update, the return value from the event handler method is used to construct a partial page response; this partial page response includes markup content that is used to update the Zone's client-side <div> element.

Where does that content come from? You inject it into your page.

Code Block
controlstrue
linenumberslanguagetruexml

<t:zone id="search" t:id="searchZone">
  <t:form t:id="searchForm" zone="searchZone">
    <t:textfield t:id="query" size="20"/>
    <input type="submit" value="Search"/>
  </t:form>
</t:zone>

<t:block id="searchResults">
  <ul>
    <li t:type="loop" source="searchHits" value="searchHit">${searchHit}</li>
  </ul>
</t:block>
Code Block
controlstrue
linenumberslanguagetruejava

  @Inject
  private Block searchResults;

  Object onSuccessFromSearchForm()
  {
    searchHits = searchService.performSearch(query);

    return searchResults;
  }

...

In many cases, you just want to re-render the Zone itself, to display updated content. In that case, you don't need a seperate separate <t:block>, instead you can use @InjectComponent to inject the Zone object itself, and return the Zone's body:

Code Block
controlstrue
linenumberslanguagetruejava

  @InjectComponent
  private Zone statusZone;

  Object onActionFromUpdateStatus()
  {
    return statusZone.getBody();
  }

How to I update multiple zones in a single event handler?

To do this, you must know, on the server, the client ids of each Zone. That's one of the reasons that you will generally set the Zone's
client id (via the Zone's id parameter), rather than let Tapestry assign a client id for you.

From the event handler method, instead of returning a Block or a Component, return a multi-zone update:

 

Code Block
controlstrue
linenumberstrue
languagejava
titleMultiple Zone Update (5.3+)

  @Inject
  private Block searchResults;

  @Inject
  private Block statusBlock;

  Object@Inject
  private AjaxResponseRenderer ajaxResponseRenderer;

  void onSuccessFromSearchForm()
  {
    searchHits = searchService.performSearch(query);

    message = String.format("Found %,d matching documents", searchHits.size());

    return new MultiZoneUpdateajaxResponseRenderer.addRender("results", searchResults).addaddRender("status", statusBlock);
  }

Note: Users of Tapestry 5.2 and earlier (which didn't support AjaxResponseRenderer) must replace that last line with: return new MultiZoneUpdate("results", searchResults).add("status", statusBlock);

AjaxResponseRenderer adds other useful commands as well. It also has the advantage that a simple return value can be returned to render content for the Zone that triggered the request.

What's that weird number in the middle of the client ids after a Zone is updated?

You might start with markup in your template for a component such as a TextField:

Code Block
controlstrue
linenumberslanguagetruexml

  <t:textfield t:id="firstName"/>

When the component initially renders as part of a full page render, you get a sensible
bit of markup:

Code Block
controlstrue
linenumberslanguagetruexml

  <input id="firstName" name="firstName" type="text">

But when the form is inside a Zone and rendered as part of a zone update, the ids get weird:

Code Block
controlstrue
linenumberslanguagetruexml

   <input id="firstName_12a820cc40e" name="firstName" type="text">

...

Instead, Tapestry creates a random-ish unique id suffix, such as "12a820cc40e" in the example; this suffix is appended to all allocated ids to ensure that they do not conflict with previously rendered ids.

Why do I sometimes get the exception "The rendered content did not include any elements that allow for the positioning of the hidden form field's element." when rendering an empty Zone?

As part of Tapestry's form processing, it must write a hidden input element with information needed when the form is submitted. Since the content of a Zone may be changed or removed, a hidden field is created just for the Zone, separate from the rest of the enclosing form.

At the same time, Tapestry wants to position the <input> field in a valid location, and HTML defines some constraints for that; an input field must appear inside a <p> or <div> element. If your zone is initially empty, there's no place to put the hidden element, and Tapestry will complain.

The solution is simple: just add a <div> element to the body of the zone. This ensures that there's a place for the hidden input field.  An empty <div> element (even one containing a hidden form field) will not affect page layout.

Wiki Markup
{scrollbar}