渲染 h:panelGroup 位于 c:forEach 内时出现错误的 id

fac*_*or5 5 jboss jstl richfaces jsf-2

我有一个页面,我在其中渲染一些 h:panelGroup 面板。这些面板在启动时作为在插件注册表中注册的插件来实现。插件 api 的一部分是一个自定义 jsf 组件,我在其中获取扩展点的注册插件,并按路径包含它们的 Facelet 模板:

<c:forEach items="#{pluginRegistry.getPlugins(point)}" var="extension">
    <ui:include src="#{extension.path}" />
</c:forEach>
Run Code Online (Sandbox Code Playgroud)

我包含面板的页面如下所示:

<h:panelGrid id="dashboard" columns="3">
    <cmf:insertPageFragments point="dashboardExtensionPoint" />
</h:panelGrid>
Run Code Online (Sandbox Code Playgroud)

对于每个面板,都有如下所示的 Facelet 模板:

<rich:panel id="caseDetailsPanel" header="panel label">
    <!-- panel content -->
</rich:panel>
Run Code Online (Sandbox Code Playgroud)

现在的问题是,pluginsRegistry 返回的列表中的第一个面板是在页面中呈现的,其中包含提供的 id,例如 formId:caseDetailsPanel。其余的都生成了像 formId:j_idt223 这样的 id!显然,如果我想重新渲染一些面板,我不能这样做。

当环境是 jboss AS 7.1 和 JSF 2.1、richfaces 4.2.3.Final 时,就会发生这种情况。当部署在 jboss-eap-6.1 上时,一切看起来都很好,但现在我无法使用这个 jboss 版本。

关于如何解决此问题有什么建议吗?

Bal*_*usC 6

不能有多个具有相同 ID 的 JSF 组件。每个 JSF 组件都必须有一个唯一的 ID。使用 JSTL 动态创建 JSF 组件时,需要手动分配并确保唯一 ID,否则 JSF 将丢弃提供的 ID 并自动生成唯一 ID。

有多种方法可以实现这一点,具体取决于具体的功能需求和现有代码。

  1. 使用 的迭代索引<c:forEach>

    <c:forEach ... varStatus="loop">
        ...
        <rich:panel id="caseDetailsPanel_#{loop.index}" ...>
    
    Run Code Online (Sandbox Code Playgroud)

    这将根据当前迭代索引生成caseDetailsPanel_0、等。caseDetailsPanel_1

  2. 使用当前迭代项的唯一标识符。根据到目前为止提供的信息,尚不清楚是否有任何信息,因此这里只是一个虚构的示例,假设后面的类#{extension}具有id表示技术数据库标识符的属性。

    <c:forEach ... var="extension">
        ...
        <rich:panel id="caseDetailsPanel_#{extension.id}" ...>
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果需要,请将 #1 或 #2 包装在<f:subview>具有唯一标识符的 a 中,这样您就不需要修改包含内容。

    <c:forEach ... varStatus="loop">
        <f:subview id="panel_#{loop.index}">
            <ui:include ... />
    
    Run Code Online (Sandbox Code Playgroud)

    围绕它创建<f:subview>一个新的NamingContainer,所以你最终会得到formId:panel_0:caseDetailsPanelformId:panel_1:caseDetailsPanel等等。

一个完全不同的替代方案是使用<ui:repeat>而不是<c:forEach>. 它<ui:repeat>不在视图构建期间运行,而是在视图渲染期间运行。这样,<rich:panel id="caseDetailsPanel">组件树中实际上只有一个组件,在生成 HTML 期间会多次重用该组件,JSF 将负责使用索引生成正确的 ID,<ui:repeat>如下所示formId:repeatId:0:caseDetailsPanel。然而,这反过来可能会导致麻烦,<ui:include>因为它也在视图构建期间运行,因此无法得到控制#{extension}