编辑:2017-04-28 这里描述了完全相同的问题(不同的情况/应用程序):Process f:viewParam only on page load
Primefaces 6.1.RC2
JSF 莫哈拉 2.3.0
我已经有一个基于 Java backing-bean 的解决方法(如下所述),用于解决以下p:dataTable
原因的问题,但我对这种解决方法不太满意,我想p:dataTable
更好地理解行编辑的行为,如果可能的话我会想为我的问题找到一个纯 XHTML 级别的解决方案。(顺便说一句,我在其他方面非常有经验p:dataTable
,多年来我已经将其用于一些非常复杂的应用程序。)
这与 中的错误或错误无关p:dataTable
,但它在行编辑期间的行为方式在一种情况下给我带来了问题。
以下代码示例完全简化并适用于本论坛。
我有一个实体元素,它有一个关系List<Link> getLinks()
,其中链接也是一个实体。
Element 有一个编辑器edit.xhtml
。
目的是拥有一个links_editor.xhtml
可以嵌入到edit.xhtml
.
有一个符合 CDI 的@ViewScoped @Named
支持 bean Manager
。
edit.xhtml 依赖于f:viewParam
加载一个元素进行编辑:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{manager.id}"/>
</f:metadata>
</f:view>
在支持 bean 中的位置Manager
:
public void setId(Long id) {
if (id != null) {
//load an Element from database for editing by id
并且在links_editor.xhtml
:
<cc:implementation>
<div id="#{cc.clientId}">
<p:growl id="testgrowl"/>
<p:dataTable
id="links_table"
editable="true"
var="link"
value="#{cc.attrs.element.links}"
>
<p:ajax
event="rowEdit"
listener="#{cc.attrs.manager.onLinkRowEdit}"
update="#{cc.clientId}:testgrowl"
/>
<p:column headerText="Link title">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.name}" />
</f:facet>
<f:facet name="input">
<p:inputText id="name" value="#{link.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Link URL">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.urlAsString}" />
</f:facet>
<f:facet name="input">
<p:inputText id="url" value="#{link.urlAsString}"/>
<p:message
for="url"
display="icon"
/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
行编辑监听器:
public void onLinkRowEdit(RowEditEvent event) {
Link link = (Link) event.getObject();
try {
checkLink(link); //throws if URL string malformed
JsfUtil.addInfoMessage("DEBUG: Link: "+link);
} catch (LocalUpdateException ex) {
JsfUtil.addErrorMessage(ex.getMessage());
}
}
(JsfUtil
显然只是利用FacesContext.getCurrentInstance().addMessage(...)
)
问题/担忧:
p:dataTable
如果我第一次编辑 Link 行,然后使用“tick save”,onLinkRowEdit
则调用侦听器,但诊断显示该值似乎没有改变。原因是它f:viewParam
被调用:
<f:viewParam name="id" value="#{manager.id}"/>
这(通过未详细显示的路由)Element
再次从数据库加载实体 via setId(Long id)
,因此在复合组件中edit_links.xthml
这实质上会重置#{cc.attrs.element.links}
,因此任何更改都将被丢弃。
有趣的是,如果(不重新加载整个@ViewScoped 页面)第二次编辑未调用的同一p:dataTable
行,然后它会按需要工作。f:viewParam
一种解决方法(相当骇人听闻)是“阻止”任何在视图范围支持 bean 中通过 id 重新加载 Element 的尝试Manager
:
public void setId(Long id) {
//HACK/WORKAROUND: prevent reload of Element by id
if (Objects.equals(id, this.id)) {
return;
}
if (id != null) {
//load an Element from database for editing by id
需要明确的是,我知道在支持 bean 中的 JSF 下频繁访问的信息的获取器中使用 @PostConstruct 和/或惰性数据库获取的常用策略。而且我不想在这里f:viewParam
完全放弃这种方法(并且它适用于同样使用相同 Manager bean 的其他情况)。
我特别感兴趣的是 Primefaces p:dataTable
:
Q1:当行信息(在这种情况下)显然已经可用时,为什么p:dataTable
需要在第一行编辑期间调用然后“勾选保存”?f:viewParam
element.links
Q2:为什么不需要在第二行编辑期间p:dataTable
调用然后“勾选保存”?f:viewParam
Q3:是否有一种基于 JSF XHTML 的方法来防止在 rowEdit 然后“勾选保存”(包括第一次)期间p:dataTable
调用?f:viewParam
更新:2017-04-21:现在有一个适用于 NetBeans 8.2 的迷你测试 Web 应用程序,在以下位置演示了该问题:
https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam
请下载主 ZIP 存档,解压缩,然后在 NetBeans IDE 8.2 中打开它。您不需要 Git 克隆项目。确保将 Glassfish-4.1.1 设置为项目的服务器。
那里的自述文件和网络应用程序测试页面本身都提供了重现问题(或与我有关的行为)的精确步骤。
我已经投入了一些精力来分析这个,因为我p:dataTable
在编辑表单中使用了很多“嵌入” f:viewParam
,并且我想更好地理解这个问题,即使它不是一个实际的问题p:dataTable
。