【问题标题】:Duplicate component ID in JSF using composite component twice in view在视图中使用复合组件两次在 JSF 中重复组件 ID
【发布时间】:2016-01-20 09:21:57
【问题描述】:

我在公司“继承”了一个 JSF 2 (JSF 2.2.7) 应用程序并面临 java.lang.IllegalStateException,因为两个组件似乎具有相同的 ID。

视图的结构如下(我提取了相关代码以进行说明,它可能包含一些拼写错误/无效的语法,因为我更改了一些名称):

<p:commandButton id="editButton"
   action="#{controller.prepareItem()}"
   update=":itemEditDlg" oncomplete="PF('itemtEditDlg').show()" />


<comp:editItemDlg id="itemEditDlg"  />

<p:dialog id="anotherDlg" >
   <h:form id="anotherForm">
      <c:forEach items="#{controller.allArgs}" var="arg" >
         <!-- next line is the problem -->
         <comp:mycomponent arg="#{arg}"  />
      </c:forEach>
   </h:form>
</p:dialog>

mycomponent.xhtml 如下所示:

<cc:interface>
    <cc:attribute name="arg" required="true" />
</cc:interface>
<cc:implementation>
    <p:inputText id="argValue" value="#{cc.attrs.arg}" />
    <p:message id="argValueMessage" for="argValue" />
</cc:implementation>

重要提示:mycomponent 组件也在 editItemDlg 中使用(与“anotherDlg”中的方式相同),即在对话框和 forEach 循环中)

如果我点击编辑按钮,我会得到:

java.lang.IllegalArgumentException: Component ID anotherForm:j_idt192:argValue  
has already been found in the view.

这很奇怪,因为在这种情况下“anotherDlg”不是开放式的,但显然已经渲染了。

我在 StackTrace 中获得以下信息(仅显示相关部分):

         +id: j_idt192
             type: javax.faces.component.UINamingContainer@399bd0dc
              +id: j_id2
               type: javax.faces.component.UIPanel@24ad3910
                +id: argValue  <===============
                 type: org.primefaces.component.inputtext.InputText@687d5c3f
                +id: argValueMessage
                 type: org.primefaces.component.message.Message@7e3361b0
                +id: argValue  <===============
                 type: org.primefaces.component.inputtext.InputText@5f52aa8a
                +id: argValueMessage
                 type: org.primefaces.component.message.Message@2c3a7aea

所以不知何故这些组件被渲染了两次,但我不知道为什么。

我已经经历了SO answer,但我无法确定列出的原因中的哪一个是我的问题。我不使用任何绑定。

到目前为止,我尝试了什么:明确设置 id,即用 包围 mycomonent,将循环计数器作为 ID 传递给组件等。但没有成功。我认为问题无法在 mycomponent 内解决。我发现的唯一解决方法是制作 mycomponent 的物理副本并在我的 anotherForm 中引用该副本(这样 editItemDlg 和 anotherDlg 不使用相同的组件)。

感谢任何帮助

【问题讨论】:

  • 经过仔细检查,堆栈跟踪中的树确实有问题。复合组件的实现被复制回同一个复合实例。这个不对。该问题的原因在目前提供的信息中不可见。请以 MCVE 格式 (stackoverflow.com/tags/jsf/info) 发布有问题的代码,并尝试将 Mojarra 升级到最新版本(当前为 2.2.12),以排除已经修复的错误。
  • @BalusC 与 2.2.12 相同的问题。我想我需要一些时间来创建一个实际运行的最小项目。
  • 我在使用 Mojarra 2.2.7 时遇到了同样的问题。这个问题有什么进展吗?
  • 对我来说似乎很奇怪的是生成的 id 序列被破坏了。注释过于严格,无法在此处粘贴组件树转储,但简而言之 - 看到生成的组件 ID 从 j_idt1 到 j_idt65 的顺序完美,然后它们突然中断到 j_idt311,然后继续使用 j_idt66。并在这个地方显示了重复的 id found 标记。
  • @BalusC 我试图在一个简单的 MCVE 项目中重现该错误,但我没有这样做......

标签: jsf facelets composite-component


【解决方案1】:

您不应为组件上的输入文本分配 id。

如果您在表单上循环遍历一个数组,那么您的输入文本元素肯定会被创建多次。

指定的标识符在所有组件(包括构面)中必须是唯一的,这些组件是作为 NamingContainer 的最近祖先 UIComponent 的后代,或者在整个组件树的范围内(如果没有这样的祖先是 NamingContainer)。

UINamingContainer 所述。

假设您的controller.allArgs 列表中有两个项目。

您生成的输出:

<form id="anotherForm">
   <input type="text" id="**argValue**">
   <p:message>
   <input type="text" id="**argValue**">
   <p:message>
</form>

这会导致重复 id 异常。

您可以创建一个新的命名容器以保持您的 input id 唯一或在您的添加中附加索引信息。

【讨论】:

  • “您不应该为组件上的输入文本分配 id”:我认为我需要该 ID,因为 p:message 必须通过 for 属性引用组件?
  • 您生成的伪 html 代码不正确。输入字段的 id 由几个组件组成,":argValue" 只是最后一个。因此,在我的组件中指定这些 ID 时我没有看到问题。
  • 查看堆栈跟踪,您有以下 JSF 组件树: +id: j_idt192 (命名容器) +id: j_id2 (面板) +id: argValue (输入文本) +id: argValueMessage ( message) +id: argValue (input text) +id: argValueMessage (message) 你在同一个父级下有重复的 id。伪代码没有任何问题。 Balusc 答案为您的问题提供了更好的整体解决方案。请忽略获取输入文本 id 的建议,但请仔细查看您的结构是如何创建的。
  • 好的,有道理。但是如何在不给它一个我可以引用的 ID 的情况下将 p:message 用于特定的 inputText 字段?
  • 嗯,我阅读了您对 Balusc 答案的评论,我认为处理布局问题比创建手动生成客户 ID 的逻辑更容易。我不会推荐这种方法,但这个答案可以帮助你:stackoverflow.com/questions/16043218/…
【解决方案2】:

您现在拥有的是多个具有相同 ID 的 JSF 组件,这是行不通的..

当动态生成组件时,您必须将某种迭代索引附加到相应的 id。

<p:inputText id="argValue_#{bean.counter}" value="#{cc.attrs.arg}" />
    <p:message id="argValueMessage_#{bean.counter}" for="argValue" />

您可以做的最好的事情是完全删除 id 标记并让 JSF 自动生成它们。

当然,如果您不从其他地方引用这些 id。

【讨论】:

    猜你喜欢
    • 2011-06-04
    • 2012-04-11
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 2013-12-01
    • 2011-06-27
    • 2015-07-28
    • 1970-01-01
    相关资源
    最近更新 更多