In a typical master/detail scenario, a table displays a Collection of objects. There is a command component (a link or button) in each table row that performs some operation on the object for that row (for example, navigating to a separate page that shows more details about that object, or allows it to be edited).
The problem is that the command's "action" attribute points to the same backing bean method to run for each row. When the method is executed, it somehow needs to know which of the rows was actually selected.
Note: The f:setActionPropertyListener tag was added in JSF1.2. For people using JSF1.1, the Tomahawk library provides t:updateActionListener which does the same thing.
This approach causes two things to happen when a command component is clicked:
1. store the command component in a property on the backing bean, then
2. run the "action method", which can look at that property to see exactly which item was selected
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.
Each table component (h:dataTable) has a DataModel object, and this DataModel knows which is the "currently selected" row.
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.