<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like
We use a "strict" DTD to make IE follow the alignment rules. -->
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<body class="container">
<h3>AJAX Multiple Zone Update</h3>
<noscript class="js-required">
${message:javascript_required}
</noscript>
This page demonstrates how multiple zones can be updated simultaneously by using the AjaxResponseRenderer service.
<div class="eg">
<t:form class="form-horizontal">
<t:zone t:id="nameZone1" id="nameZone1">
Welcome ${name}.
</t:zone><br/>
<div class="form-group">
<t:label for="firstName" class="col-sm-2"/>
<div class="col-sm-4">
<t:textfield t:id="firstName" t:mixins="zoneUpdater"
ZoneUpdater.clientEvent="keyup" ZoneUpdater.event="firstNameChanged" ZoneUpdater.zone="nameZone1"/>
</div>
</div>
<div class="form-group">
<t:label for="lastName" class="col-sm-2"/>
<div class="col-sm-4">
<t:textfield t:id="lastName" t:mixins="zoneUpdater"
ZoneUpdater.clientEvent="keyup" ZoneUpdater.event="lastNameChanged" ZoneUpdater.zone="nameZone1"/>
</div>
</div>
<t:zone t:id="nameZone2" id="nameZone2">
Welcome ${upperCaseName}.
</t:zone><br/>
Note that the following time field does not update because it's not in the zone: ${serverTime}<br/>
</t:form>
</div>
References:
<a href="http://tapestry.apache.org/ajax-and-zones.html">Ajax and Zones</a>,
<a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/Zone.html">Zone</a>,
<a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.html">AjaxResponseRenderer</a>,
<a href="http://tinybits.blogspot.com/2010/03/new-and-better-zoneupdater.html">Inge's Zone Updater</a>,
<a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/Request.html">Request</a>,
<a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a>,
<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectComponent.html">@InjectComponent</a>,
<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">@Inject</a>,
<a href="http://tapestry.apache.org/5.4/coffeescript/zone.html">t5/core/zone</a>.<br/><br/>
<t:eventlink event="gohome">Home</t:eventlink><br/><br/>
<t:tabgroup>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/ajax/AjaxMultipleZoneUpdate.tml"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/ajax/AjaxMultipleZoneUpdate.java"/>
<t:sourcecodetab src="/web/src/main/resources/META-INF/assets/css/examples/js.css"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/mixins/ZoneUpdater.java"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/mixins/zone-updater.js"/>
</t:tabgroup>
</body>
</html>
package jumpstart.web.pages.examples.ajax;
import java.util.Date;
import jumpstart.web.pages.Index;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
@Import(stylesheet = "css/examples/js.css")
public class AjaxMultipleZoneUpdate {
// Screen fields
@Property
@Persist
private String firstName;
@Property
@Persist
private String lastName;
// Generally useful bits and pieces
@InjectComponent
private Zone nameZone1;
@InjectComponent
private Zone nameZone2;
@Inject
private Request request;
@Inject
private AjaxResponseRenderer ajaxResponseRenderer;
@Inject
private ComponentResources componentResources;
// The code
// Life-cycle stuff. Fields that are marked @Persist MUST NOT be initialized in their declarations.
void setupRender() {
if (firstName == null && lastName == null) {
firstName = "Humpty";
lastName = "Dumpty";
}
}
void onFirstNameChanged() {
firstName = request.getParameter("param");
if (firstName == null) {
firstName = "";
}
if (request.isXHR()) {
ajaxResponseRenderer.addRender(nameZone1).addRender(nameZone2);
}
}
void onLastNameChanged() {
lastName = request.getParameter("param");
if (lastName == null) {
lastName = "";
}
if (request.isXHR()) {
ajaxResponseRenderer.addRender(nameZone1).addRender(nameZone2);
}
}
public String getName() {
return firstName + " " + lastName;
}
public String getUpperCaseName() {
return getName().toUpperCase();
}
public Date getServerTime() {
return new Date();
}
Object onGoHome() {
componentResources.discardPersistentFieldChanges();
return Index.class;
}
}
.eg {
margin: 20px 0;
padding: 14px;
color: #888;
border: 1px solid #ddd;
border-radius: 6px;
-webkit-border-radius: 6px;
-mox-border-radius: 6px;
}
.js-required {
color: red;
display: block;
margin-bottom: 14px;
}
.js-recommended {
color: red;
display: block;
margin-bottom: 14px;
}
/**
* A simple mixin for attaching javascript that updates a zone on any client-side event.
* Based on http://tinybits.blogspot.com/2010/03/new-and-better-zoneupdater.html
*/
package jumpstart.web.mixins;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ClientElement;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.InjectContainer;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
public class ZoneUpdater {
// Parameters
/**
* The event to listen for on the client. If not specified, zone update can only be triggered manually through
* calling updateZone on the JS object.
*/
@Parameter(name = "clientEvent", defaultPrefix = BindingConstants.LITERAL)
private String clientEvent;
/**
* The event to listen for in your component class
*/
@Parameter(name = "event", defaultPrefix = BindingConstants.LITERAL, required = true)
private String event;
@Parameter(name = "prefix", defaultPrefix = BindingConstants.LITERAL, value = "default")
private String prefix;
@Parameter(name = "context")
private Object[] context;
/**
* The zone to be updated by us.
*/
@Parameter(name = "zone", defaultPrefix = BindingConstants.LITERAL, required = true)
private String zone;
/**
* Set secure to true if https is being used, else set to false.
*/
@Parameter(name = "secure", defaultPrefix = BindingConstants.LITERAL, value = "false")
private boolean secure;
// Useful bits and pieces
@Inject
private ComponentResources componentResources;
@Environmental
private JavaScriptSupport javaScriptSupport;
/**
* The element we attach ourselves to
*/
@InjectContainer
private ClientElement attachedTo;
// The code
void afterRender() {
String listenerURI = componentResources.createEventLink(event, context).toAbsoluteURI(secure);
javaScriptSupport.require("zone-updater").with(attachedTo.getClientId(), clientEvent, listenerURI, zone);
}
}