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 LeonardoUribe
Date Sat, 06 Aug 2011 20:31:17 GMT
Dear Wiki user,

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

The "ExecutingMethodsFromLinkButtonParameters" page has been changed by LeonardoUribe:
http://wiki.apache.org/myfaces/ExecutingMethodsFromLinkButtonParameters?action=diff&rev1=13&rev2=14

- == Handling Command components within table columns ==
+ See the updated page here:
  
- 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).
+ https://cwiki.apache.org/confluence/display/MYFACES/Executing+methods+from+link+or+button+inside+a+table
  
- 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.
- 
- == Using f:setActionPropertyListener or t:updateActionListener ==
- 
- 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:
-  {{{<h:dataTable var="emp" .... >
-  
- <h:commandLink action="#{employeeAction.prepareForEdit}">
-     <h:outputText value="#{msgs.edit}" />
-     <t:updateActionListener property="#{employeeAction.currentEmployee}" value="#{emp}"
/>
- </h:commandLink>}}}
- 
- 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.
- 
- == Using the table's DataModel ==
- 
- Each table component (h:dataTable) has a !DataModel object, and this !DataModel knows which
is the "currently selected" row.
- 
- '''1)
- 
- 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".
- 
- '''2)
- 
- 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:
- {{{
- <h:commandLink actionListener="#{employeeAction.prepareForEdit}">
-     <h:outputText value="#{msgs.edit}" />
- </h:commandLink>
- }}}
- 
- And the backing bean looks like this:
- {{{
-   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
- 
-   }
- }}}
- 
- '''3)
- 
- 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.
- 
- == Passing params with f:param ==
- 
- 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:
- 
- {{{<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>}}}
- 
- 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:
- {{{<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");}}}
- 
- 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.
- 

Mime
View raw message