我使用的是"分支"的泛面o:树,其中每个分支都有一个"叶子列表",属性为"颜色",应该在树中可编辑。
- branch 0
- leaf 0 (color = "green")
- leaf 1 (color = "yellow")
- branch 1
- leaf 0 (color = "purple")
- branch 1_0
- leaf 1 (color = "red")
- leaf 2 (color = "orange")
- leaf 3 (color = "brown")
添加/移除树枝和在任何树枝上添加树叶效果良好,符合预期。此外,对包括所有叶子列表的任何复杂树的渲染(显示具有正确值的颜色属性)都像魔术一样工作。
但是更改颜色或移除叶(因此ui:repeat
中的任何内容)只能按预期用于最后渲染的分支
其他叶/分支的"颜色"输入字段根本不起作用,ui:repeat
中的删除叶链接也不起作用。对于removeLaf(…)中的叶属性,总是传递上一个渲染分支中的相应叶。因此,在上面的示例中,单击从分支0删除yellow叶将调用removeLeaf(orange,分支0),然后它将不会删除任何内容,因为分支0没有橙色叶。
这是绑定到关键部分的代码-如果需要,还可以提供其他任何东西:
<h:form>
<o:tree value="#{treeBean.tree}" var="branchEntity" varNode="branchNode">
<o:treeNode>
<o:treeNodeItem>
<ui:repeat value="#{branchEntity.leafList}" var="leaf">
<h:panelGrid columns="2">
<p:inputText value="#{leaf.color}" />
<p:commandLink action="#{treeBean.removeLeaf(leaf, branchEntity)}" styleClass="ui-icon ui-icon-trash"
process="@form" update="@form" />
</h:panelGrid>
</ui:repeat>
<p:commandLink action="#{treeBean.addLeaf(branchEntity)}" styleClass="ui-icon ui-icon-plus"
process="@form" update="@form" />
<o:treeInsertChildren />
</o:treeNodeItem>
</o:treeNode>
</o:tree>
<p:commandButton id="save" value="Save" action="#{treeBean.save}" process="@form" update="@form" />
</h:form>
我知道嵌套的ui:repeat
有一些问题,但由于我在Mojarra 2.1.19上,我想这里的情况并非如此。如果我用一个在分支列表上迭代的ui:repeat
替换o:tree
,那么实际上嵌套两个ui:repeats
是很好的。但后来我显然失去了我需要的树功能。我刚刚测试了这一点,以验证嵌套的ui:repeat
是否正常工作。
这个问题似乎与另一个问题类似,但并不完全相同。。。
如果我用p:dataList
替换内部的ui:repeat
(如解决ui:repeat
问题的其他一些答案中所建议的,以及现在这里的BalusC答案中的建议),removeLeaf()链接将全部正常工作,但仍然只有最后一个分支的颜色输入字段将被绑定。
更新:我现在在使用p:dataList
时仔细查看了一下。我从浏览器开发工具获得的AJAX请求中的POST内容看起来不错:
javax.faces.partial.ajax=true
javax.faces.source=hForm:save
javax.faces.partial.execute=hForm
javax.faces.partial.render=hForm
hForm:save=hForm:save
hForm=hForm
hForm:oTree:0:pDataList:0:color=green
hForm:oTree:0:pDataList:1:color=yellow
hForm:oTree:1:pDataList:0:color=purple
hForm:oTree:1_0:pDataList:0:color=red
hForm:oTree:1_0:pDataList:1:color=orange
hForm:oTree:1_0:pDataList:2:color=brown
javax.faces.ViewState=-6137230173999059936:-6718691551411872927
treeBean.save()方法只是将整个Tree.toString()记录到控制台,结果如下:
[Branch [leafList=[Leaf [color=null], Leaf [color=null]]],
Branch [leafList=[Leaf [color=null]]]
[Branch [leafList=[Leaf [color=red], Leaf [color=orange], Leaf [color=brown]]]]]
如果颜色有价值!=null之前,该值保持不变,因此不会被null覆盖。我对JSF还不够深入,不知道如何调查信息在途中丢失的地方。
(我最初在JBoss EAP 6.2+Primefaces 5.2+Omnifaces 2.1上使用了Mojarra 2.1.19,但在Mojara 2.2.12、TomEE、Primeffaces 5.3+Omnifaces 2.2上也体验到了完全相同的体验。完整的Maven Eclipse示例项目可以在这里找到。我甚至直接向Branch添加了一个更简单的String属性(没有List),效果很好。)
这确实是由<ui:repeat>
中的状态管理错误引起的。它没有正确地识别出自己嵌套在另一个迭代器中,并在父迭代器的每次迭代中重新访问之前顽固地清除状态。它只识别父UIRepeat
或UIData
,但仅此而已。<o:tree>
没有也不能从UIData
扩展,不幸的是,UIRepeat
是一个特定于实现的类,因此只要你想独立于特定的JSF实现(Mojarra、MyFaces等),就不能公开使用。
最好的办法是用一个真正的UIData
组件来代替<ui:repeat>
,它具有更好的状态管理实现。我刚刚在这里尝试过,添加项目对我使用<h:dataTable>
和<p:dataList>
来说很好。由于<h:dataTable>
提供了错误的客户端ID,仅删除项目失败。它没有考虑容器客户端ID。<p:dataList>
在添加和删除项目的两种情况下都对我有效。仍然更新列表中任何绑定输入字段的服务器端模型失败,如本答案评论中详细讨论的那样。
用<p:dataList type="none">
替换整个<ui:repeat>
(如果没有type
,它将呈现<ul><li>
)是最接近的。
<p:dataList type="none" value="#{branchEntity.leafList}" var="leaf">
...
</p:dataList>
如果JSF提供了一个类似UIRepeat
的公共(标记)接口,所有中继器在管理状态时都可以检查这个接口,那么世界就会简单得多。