Page NavigationPage edited by Bob Harner
Comment:
Added note about URL response only working for non-Ajax requests in 5.3.x and earlier
Changes (1)
Full ContentPage NavigationIn essence, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself. Any individual request will be targeted at a single page. Requests come in two forms:
Component Event RequestsMain Article: Component Events Component event requests may take the form of hyperlinks (EventLink or ActionLink) or form submissions (Form). The value returned from an event handler method controls the response sent to the client web browser. The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (this is usually "action"). Further, a component event request may contain additional context information, which will be provided to the event handler method. These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, users will rarely have the chance to do so (see below). Null responseIf the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response. A page render link for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page. The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event types). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions. public Object onAction(){ return null; }
A page's activate event handler mirrors its passivate handler:
. . .
void onActivate(long productId)
{
product = productDAO.getById(productId);
}
. . .
Here's the relevant part: when the page renders, it is likely to include more component event request URLs (links and forms). The component event requests for those links and forms will also start by activating the page, before performing other work. This forms an unbroken chain of requests that include the same activation context. To some degree, this same effect could be accomplished using a persistent page value, but that requires an active session, and the result is not bookmarkable. The activate event handler may also return a value, which is treated identically to a return value of a component event request event trigger. This will typically be used in an access validation scenario. Page Navigation PatternsThis combination of action links and context and page context can be put together in any number of ways. Let's take a typical master/detail relationship using the concept of a product catalog page. In this example, the ProductListing page is a list of products, and the ProductDetails page must display the details for a specific product. Component event requests / Persistent DataIn this pattern, the ProductListing page uses action events and a persistent field on the ProductDetails page. ProductListing.html <t:loop source="products" value="product"> <a t:type="actionlink" t:id="select" context="product.id">${product.name}</a> </t:loop> ProductListing.java @InjectPage private ProductDetails details; Object onActionFromSelect(long productId) { details.setProductId(productId); return details; } ProductDetails.java @Inject private ProductDAO dao; private Product product; @Persist private long productId; public void setProductId(long productId) { this.productId = productId; } void onActivate() { product = dao.getById(productId); } This is a minimal approach, perhaps good enough for a prototype. When the user clicks a link, the component event request URL will initially be something like "http://.../productlisting.select/99" and the final render request URL will be something like "http://.../productdetails". Notice that the product id ("99") does not appear in the render request URL. It has some minor flaws:
Component Event Requests / No Persistent DataWe can improve the previous example without changing the ProductListing page, using a passivation and activation context to avoid the session and make the links more bookmarkable. ProductDetails.java @Inject private ProductDAO dao; private Product product; private long productId; public void setProductId(long productId) { productId = productId; } void onActivate(long productId) { this.productId = productId; product = dao.getById(productId); } long onPassivate() { return productId; } This change ensures that the render request URL will include the product id, i.e., "http://.../productdetails/99". It has the advantage that the connection from page to page occurs in type-safe Java code, inside the onActionFromSelect method of ProductListing. It has the disadvantage that clicking a link requires two round trips to the server. Render Requests OnlyThis is the most common version of this master/detail relationship. ProductListing.html <t:loop source="products" value="product"> <a t:type="pagelink" page="productdetails" context="product.id">${product.name}</a> </t:loop> ProductListing.java No code is needed to support the link. ProductDetails.java @Inject private ProductDAO dao; private Product product; private long productId; void onActivate(long productId) { this.productId = productId; product = dao.getById(productId); } long onPassivate() { return productId; } The setProductId() method is no longer needed. LimitationsAs your application's workflow expands, you may find that there is not a reasonable way to avoid storing some data persistently between requests, outside of the page activation context. For example, if from the ProductDetails page, the user is allowed to navigate to related pages and then back to ProductDetails, it starts to become necessary to keep passing that product id around from page to page to page. At some point, persistent values make more sense. Tapestry has several persistence strategies available, including one that stores data in URL query parameters. See Persistent Page Data for details.
Change Notification Preferences
View Online
|
View Changes
|
- [CONF] Apache Tapestry > Page Navigation confluence
- [CONF] Apache Tapestry > Page Navigation confluence
- [CONF] Apache Tapestry > Page Navigation Bob Harner (Confluence)
- [CONF] Apache Tapestry > Page Navigation Bob Harner (Confluence)