Tapestry 5.3+ New Features : Part 2

AjaxResponseRender

This is one of the most useful feature of Tapestry 5.3. There is already a concept of Zone in Tapestry for Ajax but now it is complimented by AjaxResponseRenderer. This fills a lot of gaps at least for people coming from Wicket. It is a bit similar to AjaxRequestTarget but empowered with Zones and JSON. I have compiled a small example demonstrating most of the features.

Please Note : This is only a demonstration of how AjaxResponseRenderer is used. Obviously you should always prefer the ‘Zone way’ of doing things. Only when you need a combination of zone updates(multiple), small JavaScript callbacks and JSON callbacks, you can use this service. Also when you want to do different things(explained below) in different event handlers (may be belonging to different components), this service can be of great help.

@Import(library = "testJSON.js")
public class NewAjax {
    @Inject
    private AjaxResponseRenderer ajaxResponseRenderer;

    @InjectComponent
    private Zone topZone;

    @InjectComponent
    private Zone bottomZone;

    @Inject
    private JavaScriptSupport javaScriptSupport;

    @InjectComponent
    private EventLink jsonCallbackLink;

    @Inject
    private Messages messages;

    @AfterRender
    void addJavaScript(){
        javaScriptSupport.addInitializerCall("testJSON", jsonCallbackLink.getClientId());
    }

    @OnEvent("serverAlert")
    void showAlert() {
        ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
            public void run(JavaScriptSupport javascriptSupport) {
                javascriptSupport.addScript(
                    String.format("alert('%s');", messages.get("server.hello")));
            }
        });
    }

    @OnEvent("sendJSON")
    void sendJSON() {
        ajaxResponseRenderer.addCallback(new JSONCallback() {
            public void run(JSONObject reply) {
                reply.put("message", messages.get("server.message"));
            }
        });
    }

    @OnEvent("multipleZoneUpdate")
    void showZones() {
        ajaxResponseRenderer.addRender("topZone", topZone).
            addRender("bottomZone", bottomZone);
    }

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

}

<html xmlns:t='http://tapestry.apache.org/schema/tapestry_5_1_0.xsd'>
    <head>
        <title>New Ajax Features</title>
    </head>

    <body>
        <div t:type='zone' t:id='topZone'>
             Zone ${date}
        </div>

        <a href='#' t:type='eventLink' 
           t:event='multipleZoneUpdate' t:zone='topZone' t:id='multipleZoneLink'>
            Multiple Zone Update
        </a>

        <div t:type='zone' t:id='bottomZone'>
            Bottom Zone ${date}
        </div>

        <br/>

        <a t:type='eventLink' t:zone='topZone' 
           t:id='javaScriptCallbackLink' t:event='serverAlert'>
            Show Feedback alert
        </a>

        <br/>

        <a t:type='eventLink' t:id='jsonCallbackLink' t:event='sendJSON'>
            Get alert message from server!
        </a>
    </body>

</html>
Tapestry.Initializer.testJSON = function(elementId){
    $(elementId).observe("click", function(event){

        Tapestry.ajaxRequest($(elementId).href, function(response){
            alert(response.responseJSON.message);
        });

        event.preventDefault();
    });
};
server.hello=Hello from Server!
server.message=Message from Server!!

For Multiple Zone Update

Instead of using MultiZoneUpdate, you can use AjaxRequestRenderer. The advantage is that it is now a service. You can call it from multiple event handlers present in different components handling the same event. Or imagine an event handler in a component which triggers another event that is handled by the container component. Now the component can add its internal zone and then trigger an event to which the container can respond by adding its own zone!!.

Using JavaScript callback

You can now do something on server-side and return an alert message !!

Using JSON callback

You can send a JSON response in addition to updating multiple zones !!

Tagged: , ,

7 thoughts on “Tapestry 5.3+ New Features : Part 2

  1. Howard Lewis Ship October 1, 2011 at 10:26 AM Reply

    Of course, your examples make things look more complicated than usually are in practice; in general, if you want to send back JSON from an Ajax request, just return the JSON object; if you want to update a single Zone, just return the block or component for its new content.

    AjaxResponseRenderer is for when you want to render your components & blocks to update multiple client-side Zones, and do a few other tricky things. Still great to see the coverage.

    • tawus October 1, 2011 at 11:16 AM Reply

      Hi Howard

      It is just a demonstration of the usage of AjaxResponseRenderer. I have added a note to avoid confusion

  2. Muhammad Gelbana December 26, 2011 at 5:39 AM Reply

    I was trying to only comprehend the usage of AjaxResponseRenderer but this post !..man I really learned a lot more. Thank you !

  3. pstanton January 12, 2012 at 2:15 PM Reply

    “Obviously you should always prefer the ‘Zone way’ of doing things.”

    why? I have never liked the ‘Zone way’, it is very limiting. In my experience it is a rare case that I need to update a single zone, so I always end up using MultiZoneUpdate (5.1/2) or AjaxResponseRenderer (5.3).

    • tawus January 12, 2012 at 2:36 PM Reply

      The concept of zone is spread across the tapestry-core components & mixins. Yes it has limitations but it is very easy to use and extend. AjaxResponseRenderer for me is more of a Wicket’s AjaxResponseRequest (or something like that, who remembers :)) but with the support of @Inject. You can use zone as an interface for your components and users can extend it using AjaxResponseRenderer in case they need to add more zones or custom scripts.

  4. andrei November 12, 2012 at 8:26 PM Reply

    Could you help me?
    I have problem with your example:

    java.lang.IllegalStateException
    Page must be specified before initializing for partial page render.

    Filter stack frames Stack trace

    org.apache.tapestry5.internal.services.PageRenderQueueImpl.partialRenderInitialized(PageRenderQueueImpl.java:100)
    org.apache.tapestry5.internal.services.PageRenderQueueImpl.addPartialMarkupRendererFilter(PageRenderQueueImpl.java:131)
    org.apache.tapestry5.internal.services.ajax.AjaxResponseRendererImpl.addFilter(AjaxResponseRendererImpl.java:96)
    org.apache.tapestry5.internal.services.ajax.AjaxResponseRendererImpl.addCallback(AjaxResponseRendererImpl.java:105)
    com.radiumone.post.portal.ui.app.pages.NewAjax.sendJSON(NewAjax.java:55)
    com.radiumone.post.portal.ui.app.pages.NewAjax.dispatchComponentEvent(NewAjax.java)

  5. andrei November 13, 2012 at 12:38 PM Reply

    “Only when you need a combination of zone updates(multiple), small JavaScript callbacks and JSON callbacks, you can use this service.”

    What should I use If I need not small JavaScript callbacks.
    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 90 other followers

%d bloggers like this: