Navigation between pages is achieved by using forwards, redirects and by setting the page template path.
To forward to another page using the servlet
RequestDispatcher,
set the Page's forward property. For example to forward to a page with a
path index.htm
:
/** * @see Page#onPost() */ public void onPost() { // Process form post .. setForward("index.htm"); }
This will invoke a new Page class instance mapped to the path
index.htm
.
Please note when a request is forwarded to another Page, the controls on the second page will not be processed. This prevents confusion and bugs, like a form on the second page trying to process a POST request from the first page.
When you forward to another page the request parameters are maintained. This is a handy way of passing through state information with the request. For example you could add a customer object as a request parameter which is displayed in the template of the forwarded page.
public boolean onViewClick() { Long id = viewLink.getValueLong(); Customer customer = CustomerDAO.findByPK(id); // Set the customer object as a request parameter getContext().setRequestAttribute("customer", customer); setForward("view-customer.htm"); return false; }
The snippet above forwards to the page template
view-customer.htm
:
<html> <head> <title>Customer Details</title> </head> <body> <h1>Customer Details</h1> <pre> Full Name:$customer.fullName
Email:$customer.email
Telephone:$customer.telephone
</pre> </body> </html>
Request attributes are automatically added to the Velocity Context object so are available in the page template.
Page forwarding is another way of passing information between pages. In this case you create the page to be forwarded to using the Context createPage(String) method and then set properties directly on the Page. Finally set this page as the page to forward the request to. For example:
public boolean onEditClick() { Long id = viewLink.getValueLong(); Customer customer = CustomerDAO.findByPK(id); // Create a new EditPage instance based on the specified path EditPage editPage = (EditPage) getContext().createPage("/edit-customer.htm"); editPage.setCustomer(customer); setForward(editPage); return false; }
When creating a page with the createPage()
method, ensure you prefix the page path with the "/"
character.
You can also specify the target page using its class as long as the Page has a unique path. Using this technique the above code becomes:
public boolean onEditClick() { Long id = viewLink.getValueLong(); Customer customer = CustomerDAO.findByPK(id); // Create a new EditPage instance based on its class EditPage editPage = (EditPage) getContext().createPage(EditPage.class); editPage.setCustomer(customer); setForward(editPage); return false; }
This Page forwarding technique is best practice as it provides you
with compile time safety and alleviates you from having to specify page
paths in your code. Please always use the Context
createPage()
methods to allow Click to inject
Page dependencies.
Although uncommon it is possible to map more than one path to the
same class. In these cases invoking Context
createPage(Class)
will throw an exception, because
Click will not be able to determine which path to use for the Page.
An alternative method of forwarding to a new page is to simply set the current Page's path to the new page template to render. With this approach the page template being rendered must have everything it needs without having its associated Page object created. Our modified example would be:
public boolean onViewClick() { Long id = viewLink.getValueLong(); Customer customer = CustomerDAO.findByPK(id); addModel("customer", customer); // Set the Page's path to a new value setPath("view-customer.htm"); return false; }
Note how the customer
object is passed through to
the template in the Page model. This approach of using the Page model is
not available when you forward to another Page, as the first Page object is
"destroyed"
before the second Page object is created and any model values would be lost.
Redirects are another very useful way to navigate between pages. See HttpServletResponse. sendRedirect (location) for details.
The great thing about redirects are that they provide a clean URL in the users browser which matches the page that they are viewing. This is important for when users want to bookmark a page. The downside of redirects are that they involve a communications round trip with the users browser which requests the new page. Not only does this take time, it also means that all the page and request information is lost.
An example of a redirect to a logout.htm
page is
provided below:
public boolean onLogoutClick() { setRedirect("/logout.htm"); return false; }
If the redirect location begins with a "/" character
the redirect location will be prefixed with the web applications context
path. For example if an application is deployed to the context
"mycorp"
calling
setRedirect(
will redirect the request to: "/customer/details.htm"
)"/mycorp/customer/details.htm"
.
You can also obtain the redirect path via the target Page's class. For example:
public boolean onLogoutClick() { String path = getContext().getPagePath(Logout.class); setRedirect(path); return false; }
Note when using this redirect method, the target Page class must have a unique path.
A short hand way of redirecting is to simply specify the target Page class in the redirect method. For example:
public boolean onLogoutClick() { setRedirect(Logout.class); return false; }
You can pass information between redirected pages using URL request parameters. The ClickServlet will encode the URL for you using HttpServletResponse.encodeRedirectURL (url).
In the example below a user will click on an OK button to confirm
a payment. The onOkClick()
button handler
processes the payment, gets the payment transaction id, and then
redirects to the trans-complete.htm
page with the
transaction id encoded in the URL.
public class Payment extends Page { .. public boolean onOkClick() { if (form.isValid()) { // Process payment .. // Get transaction id Long transId = OrderDAO.purchase(order); setRedirect("trans-complete.htm?transId=" + transId); return false; } return true; } }
The Page class for the trans-complete.htm page can then get the
transaction id through the request parameter "transId"
:
public class TransComplete extends Page { /** * @see Page#onInit() */ public void onInit() { String transId = getContext().getRequest().getParameter("transId"); if (transId != null) { // Get order details Order order = OrderDAO.findOrderByPK(new Long(transId)); if (order != null) { addModel("order", order); } } } }