Written by Duncan
Mills, Oracle Corporation
April, 2005
Defining the Problem
One of the really neat features of JavaServer Faces as a technology is the
capability to very simply create multi-row editiable tables using the various
dataTable components. Sometimes, however, you might want to do things in an
old-fashioned way where you have a tabular view of read only data, from
which you select a commandLink (hyperlink) or some other UI element to drill
down into an edit screen for that particular record. An example of this is shown
here:
Fig 1: the drilldown UI
(Note that in the above figure I've superimposed the two screens for illustration.
The solution as it stands will bring up the edit screen in the same window as
the tabular list. A pop up window version is possible, however, if you use the
ADF
Faces component set)
The important thing here is that I want to use the same drilldown screen to
edit or create a new record and I want to be able to choose to save my changes
or cancel on navigation back from the edit/drilldown screen.
Setup
To illustrate all of this in a simple way I'll use a simple collection of Contact
beans:
The Contact Bean
package com.groundside.jsf;
public class Contact {
String _firstName;
String _lastName;
int _age;
int _contactId = 0;
public Contact( int contactId,
String
firstName,
String
lastName,
int age)
{
_contactId = contactId;
_firstName = firstName;
_lastName = lastName;
_age = age;
}
Each of the pages has a request scope backing bean, additionally the Neighbors
object is exposed as a session scoped bean and there is a request scope editContact
managed bean of type Contact used to transfer the current row from the
tabular screen to the edit screen. The complete faces-config is available here.
And for reference, here are the backing beans for the two pages:
Getting to the edit screen with a new record is trivial, we just have to navigate
there and let Faces take care of creating a new empty Contact bean for that
page:
public String newButtonAction()
{
return "drilldown";
}
Navigating to the edit page with an existing record involves getting the current
row from the dataTable control. Faces will have handled setting the row currency
correct based on the row you clicked on. Once we have the contact object we
pre-seed the editContact managed bean with it's content:
public String editLinkAction()
{
/* Pull out the currently selected contact */
Contact editContact = (Contact)this.getDataTable().getRowData();
/* Pre-seed the managed bean */
FacesContext ctx =
FacesContext.getCurrentInstance();
ValueBinding binding = ctx.getApplication().createValueBinding("#{editContact}");
binding.setValue(ctx,editContact);
return "drilldown";
}
Returning from the Edit Screen
On the edit screen I have two buttons:
A Cancel button which has a hardcoded navigation action of return, with
immediate set to true.
A Save button which looks up the Neighbors collection and sends the changed
Contact record back to it. In this implementation, the updateContact
method on the Neighbors object has the smarts to work out if this is indeed
an update or if this is a new record being added.
So that's one way to handle this scenario using raw JSF. It's quite
a simple solution and nicely illustrates the use of ValueBindings to keep your
code clean and uncontaminated by the servlet API.