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.
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
).
The code to render the configured fields uses a ui:repeat
en conditional ui:fragment
s (tried h:panelGroup
s 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.
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>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With