JSF, f:ajax and render…..

Designing JSF pages with the usage of the <f:ajax> tag can be a pretty frustrating affair.  For example, if you’re trying to build a table with Ajax behavior, it often won’t work the way you expect it to. For example imaging a table with a delete-button which changes the content of your table:

<h:panelGroup layout="block" 
   id="artikel_table_id" 
   binding="#{artikelTableContainer}">
	<table>
	<ui:repeat var="bookingItem" value="#{childItemController.childItems}">
		<tr>
			<td>....</td>
			<td><h:commandLink value="delete"
				actionListener="#{childItemController.remove(bookingItem.item['numpos'])}">
				<f:ajax render="artikel_table_id"/>
			    </h:commandLink>
			</td>
		</tr>
	</ui:repeat>
	</table>
....

This example won’t work even if it looks logical. The problem here is the render attribute pointing to the id of an outer h:panelGroup. This UI component tree is created during the initial build of the view.  If You’re manipulating the component references after building the view, the changes will not be reflected in the UI component tree during a ajax event life-cycle if you do not care to also execute the compete tree.

To solve this you can change the render attribute in the following way:

<f:ajax render="#{artikelTableContainer.clientId}" 
        execute="#{artikelTableContainer.clientId}"/>

In this way now you have a binding to a component instance which forces jsf to execute and to rebuild the complete UI component tree. Note:  the execution is necessary to update input fields placed within a table row.

ui:repeat versus c:forEach

At a first look it seems that between ui:repeat and c:forEach there is not big difference. This is true if only want to visualize a data set. But if you want to manipulate the entries too – e.g in a table with an embedded edit-mode than you can run in trouble if you are working with an ui:repeat. As explained in the example before, the elements inside a ui:repeat are not part of the component tree. This becomes an issue if your entries are editable. It will work on the first look if you simply submit the outer component. But in case of a JSF validation error, which is initiating the JSF-Life-Cycle the component tree will lost your entered values.

For that reason it is recommended to use a c:forEach tag instead of a ui:repeat if your data set is editable.

Enclosing Ajax Tags

If you use an enclosing ajax tag like in the following example, please note that you need to use a c:foreach instead of ui:repeat :

<h:panelGroup binding="#{artikelTableContainer}"> 
  <f:ajax onevent="updateOrderItems">
  <table>
    <c:forEach var="orderitem" items="#{childItemController.childItems}">        
     <tr> 
       <td>....</td>
       <td><h:commandLink value="delete"
        actionListener="#{childItemController.remove(bookingItem.item['numpos'])}">
      <f:ajax render="#{artikelTableContainer.clientId}" 
          execute="#{artikelTableContainer.clientId}"/>
      </h:commandLink> 
   </td> 
  </tr> 
 </c:forEach> 
</table>
</f:ajax>
</h:panelGroup>

In this case you should not call the ‘execute’ in the enclosing ajax!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.