Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF Partial Screen Update processes full component tree

I need some JSF / PrimeFaces (3.5) advice.

We have a dynamic form, the form can be configured by a form builder, and the backing bean is a glorified HashMap with some additional getters and setters like (getValueAsDate/setValueAsDate).

One of our field types allows for entering a number and when leaving the field additional information is requested and part of the form is updated. This appeared all to work nicely.

<h:panelGroup id="clientInfo" layout="block" rendered="#{field.type == 'CLIENTINFO'}">
    <h:outputLabel for="inputClientId">#{field.label}</h:outputLabel>
    <p:inputText id="inputClientId" maxlength="9" value="#{handler.property(field.id).value}">
        <p:ajax listener="#{handler.fetchClientDetails(field.id)}" partialSubmit="true" process="@this" update="@parent,:mainform:msgs"
    </p:inputText>
    <!-- Additional output text elements to display the name, address etc. -->
</h:panelGroup>

Recently we added a field which allowed for entering a java.util.Date using the PrimeFaces date picker component. After adding this field type the partial update stopped working.

<h:panelGroup id="date" layout="block" rendered="#{field.type == 'DATE'}">
    <h:outputLabel for="inputDate">#{field.label}</h:outputLabel>
    <p:calendar id="inputDate" value="#{handler.property(field.id).valueAsDate}" pattern="dd-MM-yyyy" maxlength="10">
        <f:convertDateTime pattern="dd-MM-yyyy" />
    </p:calendar>
</h:panelGroup>

When inspecting the partial result from the server we got something like the following (where 12345 is the clientId entered in the field above).

<partial-response>
    <error>
        <error-name>class java.text.ParseException</error-name>
        <error-message><![CDATA[Unparseable date: "12345"]]></error-message>
    </error>
</partial-response>

The question is basically why is it even calling the getValueAsDate method for a field that isn't a Date or when there is even no date field type on the screen? It is probably something I'm missing (or misunderstanding) about the JSF Lifecycle or how partial updates work in JSF / PrimeFaces.

Update #1:

Just noticed in another debugging session that this isn't only happening for a partial update but already when initially rendering the screen. It appears as if all EL expressions are evaluated all the time, this also results in additional properties in my backing object (when a property is requested and it doesn't exists it is created with the value null).

Update #2:

The code to render the configured fields uses a ui:repeat en conditional ui:fragments (tried h:panelGroups as well) to render the specific input element for the configured field.

<ui:repeat value=#{handler.formFields} var="field">
    <ui:fragment rendered="field.type == 'DATE'>
        <!-- Specific fragment for date field -->
    </ui:fragment>
    <ui:fragment rendered="field.type == 'TEXT'>
    </ui:fragment>
    <ui:fragment rendered="field.type == 'REGEXP'>
    </ui:fragment>
    <ui:fragment rendered="field.type == 'CLIENT'>
    </ui:fragment>
</ui:repeat>

Tried both h:panelGroup and ui:fragments combinations of the 2.

like image 612
M. Deinum Avatar asked Apr 23 '15 08:04

M. Deinum


1 Answers

This is recognizable as a Mojarra specific <ui:repeat> bug which was reported as issue 3215, fixed in 2.2.7 and backported in 2.1.29 as per issue 3221. Simply put, the issue boils down to that the <ui:repeat> didn't respect the state of its EditableValueHolder children when saving own state, hereby basically behaving as if rendered attribute of those children was never respected during state saving. One of other consequences is fleshed out in the following related Q&A: PropertyNotFoundException on conditionally rendered subclasses in ui:repeat.

Given that you're on Mojarra 2.1.x, your best bet is to upgrade to at least 2.1.29. If your environment allows it (Servlet 3.0 and such), upgrading to latest 2.2.x should also be possible.

Alternatives would be replacing Mojarra by MyFaces, or replacing <ui:repeat><ui:fragment> by <c:forEach><c:if>.

like image 134
BalusC Avatar answered Sep 23 '22 11:09

BalusC