AJAX EventLink

This page demonstrates how easily AJAX behaviour can be given to an EventLink, without writing any JavaScript. In this demonstration, note how the whole page is refreshed when you click the first link, whereas only time2 is updated when you click on the second, AJAX-enabled, link.
Refresh whole page - this EventLink is not AJAX-enabled
Refresh only server time 2 - this EventLink is AJAX-enabled

serverTime1: Thu May 23 10:26:44 EST 2013
serverTime2: Thu May 23 10:26:44 EST 2013
We gave AJAX behaviour to the second link by specifying a zone parameter on it and putting a Zone component around serverTime2.

Without zone specified on the first EventLink, clicking it results in Get/Redirect/Get.
The event handler returns a "redirect" to the page to render. This involves 2 round trips to the server.

With zone specified on the second EventLink, clicking it results in Post/Partial-Response.
The event handler returns a component or block to update. This involves only 1 round trip to the server.

References: EventLink, Ajax and Zones, Zone, Request, @Inject, @InjectComponent.

Some statistics: for this page the AJAX traffic is less than 300 bytes, whereas the non-AJAX traffic is over 9,000 bytes. The AJAX link generates 1 POST whereas the non-AJAX generates 2 GETs (which is normal for EventLink).

Home

AjaxEventLink.tml


<!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_3.xsd">
<head>
    <link rel="stylesheet" type="text/css" href="${context:css/examples/js.css}"/>
</head>
<body>
    <h1>AJAX EventLink</h1>

    <noscript class="js-required">
        ${message:javascript_required}
    </noscript>     

    This page demonstrates how easily <a href="http://en.wikipedia.org/wiki/AJAX">AJAX</a> behaviour can be given to an EventLink, 
    without writing any JavaScript.
    In this demonstration, note how the whole page is refreshed when you click the first link, whereas only time2 is updated when you 
    click on the second, AJAX-enabled, link.

    <div class="eg">
        <a t:type="eventlink" t:event="refreshPage" href="#">Refresh whole page - this EventLink is not AJAX-enabled</a><br/>
        <a t:type="eventlink" t:event="refreshZone" t:zone="time2Zone" href="#">Refresh only server time 2 - this EventLink is AJAX-enabled</a><br/><br/>

        serverTime1:  ${serverTime1}
        <t:zone t:id="time2Zone" id="time2Zone">
            serverTime2:  ${serverTime2}
        </t:zone>
    </div>

    We gave AJAX behaviour to the second link by specifying a <code>zone</code> parameter on it and putting a Zone component around serverTime2.<br/><br/>
    
    <strong>Without zone</strong> specified on the first EventLink, clicking it results in <strong>Get/Redirect/Get</strong>.<br/>
    The event handler returns a "redirect" to the <em>page to render</em>.  This involves 2 round trips to the server.<br/><br/>
    
    <strong>With zone</strong> specified on the second EventLink, clicking it results in <strong>Post/Partial-Response</strong>. <br/>
    The event handler returns a <em>component or block to update</em>.  This involves only 1 round trip to the server.<br/><br/> 

    References: 
    <a href="http://tapestry.apache.org/5.3.7/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a>, 
    <a href="http://tapestry.apache.org/ajax-and-zones.html">Ajax and Zones</a>, 
    <a href="http://tapestry.apache.org/5.3.7/apidocs/org/apache/tapestry5/corelib/components/Zone.html">Zone</a>,
    <a href="http://tapestry.apache.org/5.3.7/apidocs/org/apache/tapestry5/services/Request.html">Request</a>, 
    <a href="http://tapestry.apache.org/5.3.7/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">@Inject</a>, 
    <a href="http://tapestry.apache.org/5.3.7/apidocs/org/apache/tapestry5/annotations/InjectComponent.html">@InjectComponent</a>.<br/><br/> 
    
    Some statistics: for this page the AJAX traffic is less than 300 bytes, whereas the non-AJAX traffic is over 9,000 bytes. 
    The AJAX link generates 1 POST whereas the non-AJAX generates 2 GETs (which is normal for EventLink).<br/><br/>

    <a t:type="pagelink" t:page="Index" href="#">Home</a><br/><br/>
    
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/examples/ajax/AjaxEventLink.tml"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/examples/ajax/AjaxEventLink.java"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/css/examples/js.css"/>
</body>
</html>

AjaxEventLink.java


package jumpstart.web.pages.examples.ajax;

import java.util.Date;

import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.Request;

public class AjaxEventLink {

    // Generally useful bits and pieces
    
    @Inject
    private Request request;

    @InjectComponent
    private Zone time2Zone;

    // The code
    
    void onRefreshPage() {
        // Nothing to do - the page will call getTime1() and getTime2() as it renders.
    }

    // Isn't called if the link is clicked before the DOM is fully loaded. See
    // https://issues.apache.org/jira/browse/TAP5-1 .
    Object onRefreshZone() {
        // Here we can do whatever updates we want, then return the content we want rendered.
        return request.isXHR() ? time2Zone.getBody() : null;
    }

    public Date getServerTime1() {
        return new Date();
    }

    public Date getServerTime2() {
        return new Date();
    }
}

js.css


body            { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; color: #333;
                    line-height: 17px; }
h1              { font-size: 26px; line-height: 20px; } /* For IE 7 */
form            { margin: 0; }

.eg             { margin: 20px 0; padding: 20px; color: #888; 
                    border: 1px solid #ddd; border-radius: 4px; -webkit-border-radius: 4px; -mox-border-radius: 4px; }

a               { text-decoration: none; color: #3D69B6; }
a:hover         { text-decoration: underline; }

/* For javascript examples. */
.js-required    { color: red; display: block; margin-bottom: 14px; }
.js-recommended { color: red; display: block; margin-bottom: 14px; }

.grid           { border-collapse: collapse; border-spacing: 0; border: 1px solid #dddddd; font-size: 13px; }
.grid tr.odd        { background-color: #f8f8f8; }
.grid tr:hover      { background-color: #eeeeee; }
.grid th        { padding: 3px 5px; text-align: left; width: 130px; border: 1px solid #dddddd; 
                    font-weight: normal; background-color: #eeeeee; 
                    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbfbfb', endColorstr='#e4e4e4'); /* for IE */
                    background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#e4e4e4)); /* for webkit browsers */
                    background: -moz-linear-gradient(top, #fbfbfb, #e4e4e4); /* for firefox 3.6+ */ }
.grid td        { padding: 3px 5px; text-align:left; }