将新组件动态添加到 JSF 组件树时出现重复的 id



Using JSF 2.1、Mojarra 2.1.3、Glassfish 3.1.1 和 PrimeFaces 3.3.1

我正在尝试在 JSF 中处理 preRenderView 事件上的处理字段级安全性,并且在需要将动态组件添加到 JSF 组件树时遇到问题。在第一次渲染时,一切都很好,并且处理了字段级安全性。但是,在任何类型的更新之后,Mojarra 会抱怨重复的 id,即使通过打印到控制台,我的添加代码每次更新只运行一次。

看起来 Mojarra 没有清除组件树以进行回发,因此每个后续呈现的更新都会将组件的附加版本添加到树中。

感谢任何人都可以提供的任何帮助。下面是一些愚蠢的示例代码。在命令按钮上,单击将引发错误。

索引.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>

生命周期.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版本是否与Primefaces 3.3.1兼容。
使用最新版本的Primefaces 3.6。

最新更新