将新组件动态添加到 JSF 组件树时重复 id
Posted
技术标签:
【中文标题】将新组件动态添加到 JSF 组件树时重复 id【英文标题】:Duplicate id when dynamically adding new component to JSF component tree 【发布时间】:2012-11-21 02:25:47 【问题描述】:使用 JSF 2.1、Mojarra 2.1.3、Glassfish 3.1.1 和 PrimeFaces 3.3.1
我正在尝试在 JSF 中处理 preRenderView 事件中的字段级安全性,并且在需要将动态组件添加到 JSF 组件树时遇到问题。在第一次渲染时,一切都很好,并且处理了现场级别的安全性。然而,在任何类型的更新之后,Mojarra 抱怨重复的 id,即使通过打印到控制台,我的添加代码每次更新只运行一次。
看起来好像 Mojarra 没有为回发清除组件树,因此每个后续渲染更新都会向树中添加组件的附加版本。
感谢任何人提供的任何帮助。这是一些简化的示例代码。在 commandButton 单击时会引发错误。
index.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<f:event listener="#lifeCycle.event" type="preRenderView" />
<h:body>
<h:form id="form" prependId="false">
<h:panelGroup id="testPanel">
<h:inputText id="viewSec" value="viewSec node"/><br/>
</h:panelGroup>
<p:commandButton update="testPanel"/>
</h:form>
</h:body>
</html>
LifeCycle.java:
package com.dynamic.test;
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.component.visit.VisitContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
@ManagedBean
@RequestScoped
public class LifeCycle implements Serializable
public void event(ComponentSystemEvent event)
FacesContext facesContext = FacesContext.getCurrentInstance();
UIViewRoot root = facesContext.getViewRoot();
NodeInspector visitCallback = new NodeInspector();
root.visitTree(VisitContext.createVisitContext(FacesContext.getCurrentInstance()), visitCallback);
List<UIComponent> securityEnabledComponents = visitCallback.getSecurityEnabledComponents();
for (UIComponent securityEnabledComponent : securityEnabledComponents)
if(securityEnabledComponent.getClientId().equals("viewSec"))
List<UIComponent> childList = securityEnabledComponent.getParent().getChildren();
int targetPosition = securityEnabledComponent.getParent().getChildren().indexOf(securityEnabledComponent);
HtmlOutputText outputTextComponent = new HtmlOutputText();
outputTextComponent.setId(securityEnabledComponent.getId());
outputTextComponent.setValue(securityEnabledComponent.getAttributes().get("value"));
childList.set(targetPosition, outputTextComponent);
NodeInspector.java
package com.dynamic.test;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
public class NodeInspector implements VisitCallback
private List<UIComponent> securityEnabledComponents = new ArrayList<UIComponent>();
FacesContext facesContext = FacesContext.getCurrentInstance();
@Override
public VisitResult visit(final VisitContext context, final UIComponent target)
if(target.getClientId().equals("viewSec"))
securityEnabledComponents.add(target);
return VisitResult.ACCEPT;
public List<UIComponent> getSecurityEnabledComponents()
return securityEnabledComponents;
错误:
SEVERE: JSF1007: Duplicate component ID viewSec found in view.
... +id: j_idt2
type: <html xmlns="http://www.w3.org/1999/xhtml">
+id: j_idt3
type: javax.faces.component.UIOutput@17098e7
+id: form
type: javax.faces.component.html.HtmlForm@14677de
+id: testPanel
type: javax.faces.component.html.HtmlPanelGroup@167ab25
+id: viewSec <===============
type: javax.faces.component.html.HtmlOutputText@14a3d2e
+id: viewSec <===============
type: javax.faces.component.html.HtmlOutputText@f6a607
+id: j_idt4
type: <br/>
+id: j_idt5
type: org.primefaces.component.commandbutton.CommandButton@1380fc5
+id: j_idt6
type:
</html>...
SEVERE: Error Rendering View[/index.xhtml]
java.lang.IllegalStateException: Component ID viewSec has already been found in the view.
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:821)...
【问题讨论】:
今天早上我才弄清楚是什么导致了我的问题 - 我运行的 Mojarra 版本有很多错误,与动态修改树有关,这些错误大多已被最近解决版本(see bug report here)。在修复错误的过程中,他们似乎遇到了与我相同的问题。修改树会导致大量孤立节点闲置。这些节点实际上并不在呈现的 HTML 中,但仍然检查了 id 唯一性。 您应该发布此评论作为答案。了解一下很有用。 【参考方案1】:检查您使用的 Mojarra 版本是否与 Primefaces 3.3.1 兼容。 使用最新版本的 Primefaces 3.6。
【讨论】:
以上是关于将新组件动态添加到 JSF 组件树时重复 id的主要内容,如果未能解决你的问题,请参考以下文章