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 | ||||
---|---|---|---|---|
| ||||
<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 | ||||
---|---|---|---|---|
| ||||
@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 | ||||
---|---|---|---|---|
| ||||
@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 | ||||||
---|---|---|---|---|---|---|
| ||||||
@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 | ||||
---|---|---|---|---|
| ||||
<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 | ||||
---|---|---|---|---|
| ||||
<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 | ||||
---|---|---|---|---|
| ||||
<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} |