Overview

One of the largest changes made to Tapestry 4.1 was the rendering cycle. Traditionally, responses were made using one basic IMarkupWriter instance to capture and render output back to the browser. (this isn't entirely true, NullWriter instances are used in some instances, like rewinding Form components)

The new method looks basically the same on the surface, but rendering output is now managed by specific ResponseBuilder instances, depending on the type of request. These classes are responsible for calling AbstractComponent.html#render(IMarkupWriter writer, IRequestCycle cycle for all component renders. They are also responsible for managing javascript output from script templates.

You can always get a reference to the correct ResponseBuilder for the current request by calling cycle.getResponseBuilder() on your IRequestCycle instance.

See also: ResponseBuilder, DojoAjaxResponseBuilder, JSONResponseBuilder

Using ResponseBuilder to dynamically update content

Based on the type of request made, one of the three available ResponseBuilders will be chosen to handle it. In the case of a request made using the EventListener annotation, the builder used will (not in all cases, if you specify async=false on your annotation the request will be a normal http post) be DojoAjaxResponseBuilder.

Building on the example started in the EventListener overview, this is how you would dynamically update the contents of a component:

....

@EventListener(targets = "projectChoose", events = "onValueChanged")
public void projectSelected(IRequestCycle cycle)
{
  cycle.getResponseBuilder().updateComponent("myComponentId");
}

....

The string value passed in to updateComponent(String componentId) is the component id of the component which you would like to update.

Tapestry will correctly manage and render all javascript/form state/etc needed, depending on the component type you are requesting an update on.

Using ResponseBuilder for sending status messages and triggering client-side code

It is possible to trigger existing client-side code from a java listener method. This is made possible by ResponseBuilders addStatusMessage method.

....

@EventListener(targets = "projectChoose", events = "onValueChanged")
public void projectSelected(IRequestCycle cycle)
{
  cycle.getResponseBuilder().updateComponent("myComponentId");
  cycle.getResponseBuilder().addStatusMessage(null, "info", "A project was selected");
}

....

When the client is sent the ajax response, tapestry's javascript will 'publish' the status message at the specified topis, i.e. it will execute dojo.event.topic.publish('info','A project was selected')

You can take advantage of this behavior in several different ways:

  1. existing widgets - Dojo's Toaster is an example of a widget that is subscribed to the 'info' topic. Whenever a message is published there, it'll scroll itself into view and display it.
  2. create new widgets - And making them behave like Toaster.
  3. trigger javascript code - it's easy to triggger your code whenever a message is published. Here's some javascript that will alert the message:
    dojo.event.topic.subscribe('info', function(msg) { alert(msg); });