The fact that web browsers have a "back" button is infuriating to application developers. What right does the user have to dictate the order of navigation through the application? Whose application is this anyway?
In a truly stateless application, the browser back button is not a great hardship, because each page carrys within itself (as cookies, hidden form fields and encoded URLs) all the state necessary to process the page.
Tapestry applications can be more stateful, which is a blessing and a curse. The blessing is that the Tapestry application, running on the server, can maintain state in terms of business objects, data from databases, Enterprise JavaBeans and more. The curse is that a user hitting the back button on the browser loses synchronization with that state.
Let's use an e-commerce example. A user is browsing a list of available cameras from a product catalog. The user clicks on a Minolta camera and is presented with pictures, prices and details about the Minolta camera.
Part of the page lists similar or related items. The user clicks on the name of a similar Nikon camera and is shown the pictures, prices and details of the Nikon camera. The user then hits the browser back button, returning to the page showing the Minolta camera, and clicks the "add to shopping cart" button. Web browsers have no way of informing the server that the user has employed the back button.
Once the user clicks the link, the server replies with a response showing the contents of the shopping cart ... but what has been added to the cart, the Minolta or the Nikon? It depends on how the Tapestry application has been structured.
Presumably, the application has a single page, named ProductDetails
, that shows the pictures,
prices and details of any product. The ProductDetails
page will
have a persistent property named
product, of type Product
. Product
is a business
class that contains all that pricing and detail
information.
The question is, how is the add to shopping cart link implemented? If its logic is to add whatever the
current value of the product property is (i.e., by using an ActionLink
component or part of a form) then it will
add the Nikon camera, since that's the current product (the most recent one displayed
to the user, as far as the server is concerned ― it has no way to know the user hit
the back button and was staring at the Minolta when the link was clicked). This is the natural approach, since it
doesn't take into account the possiblility that the user worked backwards to a prior page.
On the other hand, if a DirectLink
component is used, it can encode into the
URL the primary key of
the Minolta product, and that will be the product added to the shopping cart, regardless of the
current value of the product property.
HTML Forms, controlled by the Form
component, are also
susceptible to these issues related to the browser back button. Still, there are techniques to make
even forms safe. Borrowing an idea from more traditional JavaServer Pages development, a
hidden field can be included in the form to sychronize the form and the application ... for
example, including the primary key of the Minolta or Nikon product. Tapestry includes a
Hidden
component used for just this purpose.
Finally, the ListEdit
component exists to help. It works like a Foreach
, but encodes the
number and value of the items it iterates as hidden form fields.