...
...
This solution looks something like the following:
...
When the above link is clicked, JSF will first call the setCurrentEmployee(Employee) method on the backing bean (which should store its parameter as a member on the backing bean). The prepareForEdit method can then just use that member to know which specific employee was chosen.
...
- An h:dataTable can be configured to use a !DataModel explicitly provided by your code, ie the "value" attribute of the h:dataTable can point to a backing-bean method that returns a !DataModel. If you are doing this, and the !DataModel object is cached in a member of your backing bean, then the "action method" that is triggered can simply access that member and call its getRowData() method to get the object for the "selected row".
- If the "value" attribute of the h:dataTable instead points to a backing-bean method that returns a List or similar collection, then the dataTable will internally create a !DataModel to wrap that list. You can access this DataModel instance by using the "actionListener" attribute on the command component, rather than the "action" one. The backing-bean method is then passed an ActionEvent object which contain a reference to the command-component that was clicked on; by walking up the component tree the enclosing UIData component can be found, and its DataModel then retrieved. Actually, it's even simpler, as the "getRowData" method on the UIData component can be used directly (it just delegates to the DataModel method).
The JSF page looks like this: Code Block |
---|
xml | xml
<h:commandLink actionListener="#{employeeAction.prepareForEdit}">
<h:outputText value="#{msgs.edit}" />
</h:commandLink>
And the backing bean looks like this: Code Block |
javajava |
public void prepareForEdit(ActionEvent anEvent) {
YourBeanClass tmpBean = null;
UIComponent tmpComponent = anEvent.getComponent();
while (null != tmpComponent && !(tmpComponent instanceof UIData)) {
tmpComponent = tmpComponent.getParent();
}
if (tmpComponent != null && (tmpComponent instanceof UIData)) {
Object tmpRowData = ((UIData) tmpComponent).getRowData();
if (tmpRowData instanceof YourBeanClass) {
tmpBean = (YourBeanClass) tmpRowData;
//TODO Implementation of your method
}
}
//TODO Exception Handling if UIData not found or tmpRowBean of wrong type
}
- You could also use the "binding" attribute on the h:dataTable to make it accessable from the backing bean. However component bindings have their own problems and should be avoided where possible.
...
If you are coming from Struts or some other servlet MVC framework you may have previously solved this problem by passing some kind of primary key as request parameters as part of a link, perhaps via something like this:
...
...
Using JSTL to create the above:
...
It is possible to use this approach with JSF, but it is not in the spirit of JSF; the solutions documented above are generally considered better. Nevertheless, this can be implemented as follows:
Use an f:param tag inside of the commandButton or commandLink:
...
To then get a handle to this request parameter in your "prepareEdit" method, you could do:
...
Note that in this case the parameter is a String, which you'll have to map to the appropriate object id yourself. Plus, you have extra lines of code just to get a handle to the map holding the parameters. Sure you can push that off to a utility class, but the above solutions are cleaner ways to handle this.
...