因此,经过几天的调试,我们最终能够重现复合组件ui:repeat
,p:remoteCommand
之间的一些奇怪的交互,以及我们不理解的JSF中的部分状态保存。
复合组件使用ui:repeat
迭代对象列表。在每次迭代期间,包含另一个复合组件并传递参数。
<ui:composition (...)>
<ui:repeat var="myVar" value="#{cc.attrs.controller.someList}">
<namespace:myRemoteCommand someParam="SomeParam"/>
在包含的复合组件中,有一个自动运行p:remoteCommand
使用组件界面中定义的参数调用方法。
<ui:component (...)>
<p:remoteCommand actionListener="#{someBean.someMethod(cc.attrs.someParam)}"
autoRun="true"
async="true"
global="false">
但是,在someMethod(...)
中设置断点时,会传递一个空字符串。仅当部分状态保存设置为 false 时才会出现此情况。
我们尝试了几种解决方案,以下方案似乎有效(但我们不明白为什么,也无法预见可能发生的任何其他问题):
我们可以将部分状态保存设置为true
。
我们可以将复合组件模式更改为ui:include
。
我们可以删除一个或两个复合组件,而是直接包含内容。
问题
为什么JSF会这样做?复合组件ui:repeat
和参数传递之间的这种交互是什么,这取决于我们是否使用ui:include
/部分状态保存?
我们使用的是Primefaces 5.3,Glassfish 4.1,Mojarra 2.2.12,Java 8.
答案 0 :(得分:4)
你的代码很好。只是Mojarra的<ui:repeat>
被打破了。您不是第一个面临与<ui:repeat>
的州管理相关问题的人。
问题的根本原因是#{cc}
在<ui:repeat>
需要访问树时无法使用<ui:repeat value>
。实际上,null
是#{cc}
。快速解决方法是明确推送UIRepeat#visitTree()
方法中的pushComponentToEL(facesContext, null)
。鉴于Mojarra 2.2.12,请在line 734之前添加以下行UIComponent compositeParent = getCompositeComponentParent(this);
if (compositeParent != null) {
compositeParent.pushComponentToEL(facesContext, null);
}
。
popComponentFromEL(facesContext)
并在line 767之后添加以下行if (compositeParent != null) {
compositeParent.popComponentFromEL(facesContext);
}
。
UIRepeat
如果您不是从源代码构建Mojarra,请将整个source code /WEB-INF/classes
复制到您的项目中,维护其包结构并在其上应用上述更改。 /WEB-INF/lib
中的类具有比/lib
和服务器<ui:repeat>
中的类更高的类加载优先级。我至少创建了issue 4162来解决这个问题。
另一种方法是用MyFaces替换Mojarra,或用基于UIData
的组件替换<h:dataTable>
,该组件具有状态管理权限,例如<p:dataList>
或<p:dataList type="none" var="myVar" value="#{cc.attrs.controller.someList}">
<namespace:myRemoteCommand someParam="SomeParam" />
</p:dataList>
。< / p>
{{1}}
您可能只想应用一些CSS来摆脱小部件样式(边框等),但那是trivial。