24

我知道我们不能重复我们在同一视图树中拥有的任何组件的 ID。

我有一个页面,其中包含某些条件下的其他页面像这样......

<h:panelGroup rendered="#{bean.insertMode == 'SINGLE'}">
   <ui:include src="_single.xhtml" />
</h:panelGroup> 
<h:panelGroup rendered="#{bean.insertMode == 'DOUBLE'}">
   <ui:include src="_double.xhtml" />
</h:panelGroup>

现在在这些页面中,我有“几乎”相同的组件层次结构(复杂),具有不同的操作行为(不仅是方法调用,还有视图),例如:

_single.xhtml

<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.singleAction()}" />

_double.xhtml

<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.doubleAction()}" />

我的小例子工作正常,并按预期呈现,但我明白了

java.lang.IllegalStateException: Component ID fieldID has already been found in the view.

我知道 JSF 会处理整个页面,即使它们不包括在内,这就是我收到此异常的原因。

在不更改包含页面内组件 ID 的情况下解决此问题的任何智能方法(虽然它有效,但异常很烦人并且似乎有问题)。

我也不想用一些具有不同 ID 的容器组件包装每个页面,因此它们将具有不同的 FULL ID,例如 formId:fieldID,因为母版页也指的是这些包含中的这些组件!

4

1 回答 1

34

出现重复组件 ID 错误是因为两者都包含在 JSF 组件树中。<h:panelGroup rendered="false">不会阻止它们出现在 JSF 组件树中,而是会阻止它们生成 HTML 输出。

您需要有条件地在 JSF 组件树中构建它们,而不是有条件地呈现它们的 HTML 输出。JSTL 在这方面非常有帮助,因为它在视图构建期间运行:

<c:if test="#{bean.insertMode eq 'SINGLE'}">
    <ui:include src="_single.xhtml" />
</c:if> 
<c:if test="#{bean.insertMode eq 'DOUBLE'}">
    <ui:include src="_double.xhtml" />
</c:if>

如果您使用 Mojarra,您只需确保至少使用 2.1.18 或更高版本,否则视图范围 bean 的行为将类似于请求范围 bean。

另一种方法是在src属性中使用 EL 条件运算符(它<ui:include> 本身也在视图构建期间作为标记处理程序运行):

<ui:include src="_#{bean.insertMode eq 'SINGLE' ? 'single' : 'double'}.xhtml" />

甚至insertMode直接使用作为文件名:

<ui:include src="_#{fn:toLowerCase(bean.insertMode)}.xhtml" />

无论哪种方式,您都需要绝对确保#{bean.insertMode}在视图构建期间可用,并且在回发的恢复视图阶段与初始渲染期间完全相同的值可用,否则视图可能会使用错误的包含和 JSF 无法再解码正确的输入和命令。此外,当您想在回发期间更改包含时,您确实需要重建视图(返回非null/ void),或发送重定向。

也可以看看:

于 2013-09-12T16:13:20.643 回答