JSF 局部屏幕更新处理完整的组件树
JSF Partial Screen Update processes full component tree
我需要一些 JSF / PrimeFaces (3.5) 的建议。
我们有一个动态表单,表单可以由表单构建器配置,支持 bean 是一个美化的 HashMap
,带有一些额外的 getter 和 setter,例如 (getValueAsDate
/setValueAsDate
).
我们的一种字段类型允许输入数字,离开该字段时需要额外的信息并更新部分表格。这似乎一切正常。
<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>
最近我们添加了一个字段,允许使用 PrimeFaces 日期选择器组件输入 java.util.Date
。添加此字段类型后,部分更新停止工作。
<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>
在检查来自服务器的部分结果时,我们得到如下内容(其中 12345 是在上面的字段中输入的 clientId)。
<partial-response>
<error>
<error-name>class java.text.ParseException</error-name>
<error-message><![CDATA[Unparseable date: "12345"]]></error-message>
</error>
</partial-response>
问题基本上是为什么它甚至为不是 Date
的字段调用 getValueAsDate
方法,或者当屏幕上什至没有日期字段类型时?关于 JSF 生命周期或部分更新在 JSF / PrimeFaces 中的工作方式,这可能是我遗漏(或误解)的内容。
更新#1:
刚刚在另一个调试会话中注意到,这不仅发生在部分更新中,而且在最初渲染屏幕时就已经发生了。似乎所有 EL 表达式一直都在求值,这也会在我的支持对象中产生额外的属性(当请求 属性 但它不存在时,它是用值 null
创建的).
更新#2:
呈现配置字段的代码使用 ui:repeat
en 条件 ui:fragment
s(也尝试 h:panelGroup
s)来呈现配置字段的特定输入元素。
<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>
尝试了 h:panelGroup
和 ui:fragments
两种组合。
这被认为是 Mojarra 特定的 <ui:repeat>
错误,报告为 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。
鉴于您使用的是 Mojarra 2.1.x,最好的办法是至少升级到 2.1.29。如果您的环境允许(Servlet 3.0 等),升级到最新的 2.2.x 应该也是可能的。
备选方案是用 MyFaces 替换 Mojarra,或者用 <c:forEach><c:if>
替换 <ui:repeat><ui:fragment>
。
我需要一些 JSF / PrimeFaces (3.5) 的建议。
我们有一个动态表单,表单可以由表单构建器配置,支持 bean 是一个美化的 HashMap
,带有一些额外的 getter 和 setter,例如 (getValueAsDate
/setValueAsDate
).
我们的一种字段类型允许输入数字,离开该字段时需要额外的信息并更新部分表格。这似乎一切正常。
<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>
最近我们添加了一个字段,允许使用 PrimeFaces 日期选择器组件输入 java.util.Date
。添加此字段类型后,部分更新停止工作。
<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>
在检查来自服务器的部分结果时,我们得到如下内容(其中 12345 是在上面的字段中输入的 clientId)。
<partial-response>
<error>
<error-name>class java.text.ParseException</error-name>
<error-message><![CDATA[Unparseable date: "12345"]]></error-message>
</error>
</partial-response>
问题基本上是为什么它甚至为不是 Date
的字段调用 getValueAsDate
方法,或者当屏幕上什至没有日期字段类型时?关于 JSF 生命周期或部分更新在 JSF / PrimeFaces 中的工作方式,这可能是我遗漏(或误解)的内容。
更新#1:
刚刚在另一个调试会话中注意到,这不仅发生在部分更新中,而且在最初渲染屏幕时就已经发生了。似乎所有 EL 表达式一直都在求值,这也会在我的支持对象中产生额外的属性(当请求 属性 但它不存在时,它是用值 null
创建的).
更新#2:
呈现配置字段的代码使用 ui:repeat
en 条件 ui:fragment
s(也尝试 h:panelGroup
s)来呈现配置字段的特定输入元素。
<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>
尝试了 h:panelGroup
和 ui:fragments
两种组合。
这被认为是 Mojarra 特定的 <ui:repeat>
错误,报告为 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。
鉴于您使用的是 Mojarra 2.1.x,最好的办法是至少升级到 2.1.29。如果您的环境允许(Servlet 3.0 等),升级到最新的 2.2.x 应该也是可能的。
备选方案是用 MyFaces 替换 Mojarra,或者用 <c:forEach><c:if>
替换 <ui:repeat><ui:fragment>
。