AJAX Multiple Zone Update

This page demonstrates how multiple zones can be updated simultaneously by using the AjaxResponseRenderer service.
Welcome Humpty Dumpty.

Welcome HUMPTY DUMPTY.

Note that the following time field does not update because it's not in the zone: Wed Nov 22 04:08:14 EST 2017
References: Ajax and Zones, Zone, AjaxResponseRenderer, Inge's Zone Updater, Request, ComponentResources, @InjectComponent, @Inject, t5/core/zone.

Home


<!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 &nbsp; 
     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);
    }
}

The file was not found. Path given was /WEB-INF/sourcecode/web/src/main/java/jumpstart/web/mixins/zone-updater.js