JSF: update single entry in a datalist like component

Goal

To update a single entry in a datalist like component in a JSF application

Description

Recently, in a project I was working on, there was the need to create a GUI that would make it possible to show a list of elements that, each, could be made editable and, when editable, the interface of that element would change so that it could present the editable components.

This recipe explains how to achieve this kind of behaviour.

How to

Use a view build time tag such as JSTL’s forEach instead of a view render time tag such as Primefaces’ dataList or dataTable, as follows:

...
<h:form id="form">
  ...
  <c:forEach items="#{projectBean.refundRequestHelper.refundRequests}"
     var="refundRequest" varStatus="refundRequestStatus">
    <h:panelGroup id="refundRequest#{refundRequestStatus.index}" layout="block">
      <ui:include src="view/refund_request/refund_request_view.xhtml" />
     </h:panelGroup>
  </c:forEach>
  ...
</h:form>
...

And make sure you specify a panel id which uses the varStatus variable to force a different name for each iteration. From now on, we may refer to the wrapping panel group whose name was specified as “refundRequest#{refundRequestStatus.index}”, in the included file refund_request_view.xhtml, as :form:refundRequest#{refundRequestStatus.index}. A simplification of that file with the most relevant contents is shown next:

<p:panel collapsed="#{projectBean.refundRequestHelper.collapsed}" toggleable="true">
  ...
  <p:panel collapsed="#{projectBean.refundRequestActivityMetricHelper.collapsed}" toggleable="true">
    <f:facet name="header">
      <h5>
        <i class="fa fa-book" title="#{i18n['refundRequestActivityMetric.data.header']}" />
        <h:outputText value="#{' '}" />
        <h:outputFormat value="#{i18n['refundRequest.numberOfRefundRequestActivityMetrics']}">
          <f:param value="#{projectBean.refundRequestActivityMetricHelper.
                            getSize(refundRequest.refundRequestId)}" />
        </h:outputFormat>
      </h5>
    </f:facet>
    <f:facet name="actions">
      <p:commandLink disabled="#{projectBean.refundRequestActivityMetricHelper.new}"
        rendered="#{projectBean.refundRequestHelper.canEdit(refundRequest)}"
        action="#{projectBean.refundRequestActivityMetricHelper.prepareNew}"
        process="@this"
        update=":form:refundRequest#{refundRequestStatus.index}"
        styleClass="ui-panel-titlebar-icon ui-corner-all ui-state-default">
        <h:outputText styleClass="ui-icon ui-icon-document" 
          value="#{i18n['button.add']}" />
      </p:commandLink>
    </f:facet>
    ...
  </p:panel>
  ...
</p:panel>

Explanations

Now, we can update each “refundRequest” independently, because we really are able to refer to each of them. As explained by BalusC comment here, with a component such as dataList or dataTable, the server side does not generate an id per iteration. That part only occurs for the client side, which means there is no way to refer to it in an Ajax call.

Additionally, we not have to name each of the components using the varStatus variable to make sure the name of the component is unique within the view root tree. So, we now have to define each component id as follows:

<h:inputText
 id="refundRequestActivityMetricAmount#{refundRequestStatus.index}"
 styleClass="input" required="true"
 value="#{projectBean.refundRequestActivityMetricHelper.amount}" />

instead of the following, as we could have used if we were using a iteratable component such as dataTable:

<h:inputText
 id="refundRequestActivityMetricAmount"
 styleClass="input" required="true"
 value="#{projectBean.refundRequestActivityMetricHelper.amount}" />

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s