Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: restore

Wiki Markup
{scrollbar}

Ajax Components

Main article: Ajax and ZonesComponents FAQ

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

...

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

Code Block
controlstrue
languagexml
<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
languagejava
  @Inject
  private Block searchResults;

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

    return searchResults;
  }

So, when the search form is submitted, the resulting search hits are collected. In the same request, the searchResults block is rendered, package, and sent to the client. The form inside the client-side Zone <div> is replaced with the list of hits.

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

Code Block
controlstrue
languagejava
  @InjectComponent
  private Zone statusZone;

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

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

...

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

 

Code Block
controlstrue
languagejava
titleMultiple Zone Update (5.3+)
  @Inject
  private Block searchResults;

  @Inject
  private Block statusBlock;

  @Inject
  private AjaxResponseRenderer ajaxResponseRenderer;

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

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

    ajaxResponseRenderer.addRender("results", searchResults).addRender("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);

...

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

Code Block
controlstrue
languagexml
  <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
languagexml
  <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
languagexml
   <input id="firstName_12a820cc40e" name="firstName" type="text">

What's happening here is that Tapestry is working to prevent unwanted id clashes as part of the page update. In an HTML document, each id is expected to be unique; most JavaScript is keyed off of the id field, for instance.

...

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}