myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Myfaces Wiki] Update of "ExecutingMethodsFromLinkButtonParameters" by RickReumann
Date Sat, 17 Sep 2005 05:30:21 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Myfaces Wiki" for change notification.

The following page has been changed by RickReumann:
http://wiki.apache.org/myfaces/ExecutingMethodsFromLinkButtonParameters

New page:
== Execute a managed bean method based on parameters provided for a link or button, or clicking
on link/button on row to get to detail screen from master list  ==

A typical master/detail scenario:

A table displays a Collection of objects. You want be able to click on an 'edit' link or button
and be brought to the detail screen for editing the record.

If you are coming from Struts or some other servlet MVC framework your first thought would
be to pass some kind of primary key as request parameters as part of a link:

{{{<a href="/appContext/someAction.do?id=1234&userAction=prepareEdit">Edit</a>}}}

Using JSTL to create the above:
{{{
<c:url value="someAction.do" var="url">
   <c:param name="id" value="1234" />
   <c:param name="userAction" value="prepareEdit" />
</c:url>
<a href="${url}">Edit</a>}}}

With MyFaces, there are several ways to handle this. Below are three ways. (Note, I don't
like the first way, but am showing it as it might be the first one your inclined to try).

'''1) Passing params with f:param'''

The first thing you might think of doing with JSF is to mimick the typical way you've passed
parameters in a link. To do this with JSF, you could use the f:param tag inside of commandButton
or commandLink:
{{{<t:dataTable var="emp" .... >

 <h:commandLink id="editLink" action="#{employeeAction.prepareEdit}">
  <h:outputText value="#{msg.edit}"/>
  <f:param name="id" value="#{emp.id}"/>
</h:commandLink>}}}

To then get a handle to this request parameter in your "prepareEdit" method, you could do:

{{{FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
String employeeID = (String) map.get("id");}}}

The above will work, but I'm not too fond of this approach. For one, you'll be dealing with
a String and you'll have to conversions 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 there is a cleaner way to handle this.

'''2) Using <t:updateActionListener  ... />'''

Before I get to using the tag, some background information...

Typically your backing bean (continuing with the example above, EmployeeAcion.java) will have
either 
1) A member property that is a bean that will hold info you want to capture (often just a
typical POJO value object)
or
2) Direct memember properties in the backing bean with getters/setters

For example EmployeeAction might have:

{{{private Employee employee; //standard POJO Value Object with properties name, id, etc
setEmployee( Employeee emp ) //
getEmployee() //

or

String name; //getName/setName
Integer id;  //getId/setId}}}

both techniques are valid although I like the first approach. Since I usually have ValueObjects
that are used in different places, it makes sense to me to just make the POJO a managed property
of your backing bean. The only caveat is that you'll usually need to create a managed bean
reference to your property in your faces-config. 

ie:

{{{<managed-bean>
    <managed-bean-name>employeeAction</managed-bean-name>
    <managed-bean-class>net.reumann.EmployeeAction</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
 	<managed-property>
        <property-name>employee</property-name>
        <value>#{employee}</value>
    </managed-property> 
</managed-bean>}}}

The above will make sure that EmployeeAction always has an instance of Employee set.

Now to use the t:updateActionListener tag you could just do:
 {{{<t:dataTable var="emp" .... >
 
<t:commandLink action="#{employeeAction.prepareForEdit}">
    <h:outputText value="#{msgs.edit}" />
    <t:updateActionListener property="#{employeeAction.employee.id}" value="#{emp.id}"
/>
</t:commandLink>}}}

When the above link is clicked it will set the id of the Employee object in our EmployeeAction
bean.

If you were using id directly as a property in your EmployeeAction, the link would look like...

{{{<t:commandLink action="#{employeeAction.prepareForEdit}">
    <h:outputText value="#{msgs.edit}" />
    <t:updateActionListener property="#{employeeAction.id}" value="#{emp.id}" />
</t:commandLink>}}}

I really like this approach. It's clean and ex-Struts users can think of it as sort of like
having your ActionForm properties set based on any request parameters submited. There is no
need to have to get a handle to the Map backing the Request parameters like there is in the
first approach.

'''3) Getting handle to DataModel Row.'''

Another approach is if you are using a DataTable backed by a DataModel you can get a handle
to the object that is backing the row. So if the user clicks on the "edit" link on the third
row, you can get a handle to the Emloyee object that backs that row in your EmployeeAction.
The edit link would be simple...
{{{<t:dataTable var="emp" value="#{employeesListBean.employeesModel}" ... >
 
<t:commandLink action="#{employeeAction.prepareForEdit}" value="#{msgs.edit}"/>}}}

In prepareForEdit we could get a handle to the Employee of that row....

{{{employee = (Employee)getEmployeesListBean().getEmployeesModel().getRowData();}}}

Note, our DataModel in this case happens to be created in a class called "EmployeeListBean"
which is managed property of our EmployeeAction...

{{{<managed-bean>
    <managed-bean-name>employeeAction</managed-bean-name>
    <managed-bean-class>net.reumann.EmployeeAction</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
 	<managed-property>
        <property-name>employee</property-name>
        <value>#{employee}</value>
    </managed-property> 
    <managed-property>
        <property-name>employeesListBean</property-name>
        <value>#{employeesListBean}</value>
    </managed-property>
</managed-bean>}}}

You could of course create your DataModel directly in the EmployeeAction class, in which case
you wouldn't need the extra class (EmployeeListBean) holding the DataModel (I like to have
it separate though in case other classes want to use it).

The other thing to note is that if your DataModel for the form doesn't have Session scope,
you'll need to do something like t:saveState in order to make sure the same DataModel is present
when you click on your link. In this example we would add x:saveState some place after f:view:

{{{<f:view>
    <t:saveState id="employeesListBean" value="#{employeesListBean}"/>}}}
    
In closing, if you want to see these last two approaches in some example code.... http://www.reumann.net/reumann/jsf/jsf_employees/

Mime
View raw message