【问题标题】:Duplicate id when dynamically adding new component to JSF component tree将新组件动态添加到 JSF 组件树时重复 id
【发布时间】: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 唯一性。
  • 您应该发布此评论作为答案。了解一下很有用。

标签: jsf dynamic primefaces components mojarra


【解决方案1】:

检查您使用的 Mojarra 版本是否与 Primefaces 3.3.1 兼容。
使用最新版本的 Primefaces 3.6。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2012-03-17
    • 2016-08-27
    • 1970-01-01
    相关资源
    最近更新 更多