在p:datatable中找不到PrimeFaces/JSF组件ID

Kaw*_*awu 6 jsf primefaces jsf-2

我刚开始使用PrimeFaces 3.3.1从RichFaces 3和4开始.

我有一个结构的数据表:

            <f:facet name="header">
                <h:outputText value="Employees" />
            </f:facet>

            <p:column sortBy="#{emp.lastName}">
                <f:facet name="header">
                    <h:outputText value="Last Name" />
                </f:facet>
                <h:outputText value="#{emp.lastName}" />
            </p:column>

            <p:column>
                <f:facet name="header">
                    <h:outputText value="First Name" />
                </f:facet>
                <h:outputText value="#{emp.firstName}" />
            </p:column>

            ...

            <p:column>
                    <p:commandButton icon="ui-icon ui-icon-trash"
                                     value="Remove"
                                     process="@this"
                                     update="employee-remove-dialog"
                                     oncomplete="employeeRemoveDialog.show();">
                        <f:setPropertyActionListener target="#{employeeManager.currentEmployee}" value="#{emp}" />
                    </p:commandButton>
            </p:column>
        </p:dataTable>

        <p:dialog header="Remove Employee"
                  modal="true"
                  appendToBody="true"
                  widgetVar="employeeRemoveDialog"
                  id="employee-remove-dialog">
            <h:outputText value="Remove employee #{employeeManager.currentEmployee.fullName}?" />
            <f:facet name="footer">
                <p:commandButton icon="ui-icon ui-icon-check"
                                 value="OK"
                                 action="#{employeeManager.deleteEmployee}"
                                 process="@this"
                                 update="employee-list"
                                 oncomplete="employeeRemoveDialog.hide();" />
                <p:commandButton icon="ui-icon ui-icon-close"
                                 value="Cancel"
                                 onclick="employeeRemoveDialog.hide();"
                                 ajax="false"
                                 immediate="true" />
            </f:facet>
        </p:dialog>

    </h:form>
Run Code Online (Sandbox Code Playgroud)

然而PrimeFaces引发了一个例外:

09:36:08,961 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (http-localhost-127.0.0.1-8080-1) Error Rendering View[/employeeList.xhtml]: javax.faces.FacesException: Cannot find component with identifier "employee-remove-dialog" referenced from "j_idt30:employee-list:0:j_idt41".
    at org.primefaces.util.ComponentUtils.findClientIds(ComponentUtils.java:251) [primefaces-3.3.1.jar:]
    at org.primefaces.util.AjaxRequestBuilder.addIds(AjaxRequestBuilder.java:102) [primefaces-3.3.1.jar:]
    at org.primefaces.util.AjaxRequestBuilder.update(AjaxRequestBuilder.java:90) [primefaces-3.3.1.jar:]
    at org.primefaces.renderkit.CoreRenderer.buildAjaxRequest(CoreRenderer.java:195) [primefaces-3.3.1.jar:]
    at org.primefaces.component.commandbutton.CommandButtonRenderer.encodeMarkup(CommandButtonRenderer.java:74) [primefaces-3.3.1.jar:]
    at org.primefaces.component.commandbutton.CommandButtonRenderer.encodeEnd(CommandButtonRenderer.java:49) [primefaces-3.3.1.jar:]
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.primefaces.component.datatable.DataTableRenderer.encodeRegularCell(DataTableRenderer.java:780) [primefaces-3.3.1.jar:]
    at org.primefaces.component.datatable.DataTableRenderer.encodeRow(DataTableRenderer.java:741) [primefaces-3.3.1.jar:]
    at org.primefaces.component.datatable.DataTableRenderer.encodeTbody(DataTableRenderer.java:645) [primefaces-3.3.1.jar:]
    at org.primefaces.component.datatable.DataTableRenderer.encodeRegularTable(DataTableRenderer.java:248) [primefaces-3.3.1.jar:]
    at org.primefaces.component.datatable.DataTableRenderer.encodeMarkup(DataTableRenderer.java:220) [primefaces-3.3.1.jar:]
    at org.primefaces.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:107) [primefaces-3.3.1.jar:]
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1786) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.render.Renderer.encodeChildren(Renderer.java:168) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.primefaces.renderkit.CoreRenderer.renderChild(CoreRenderer.java:55) [primefaces-3.3.1.jar:]
    at org.primefaces.renderkit.CoreRenderer.renderChildren(CoreRenderer.java:43) [primefaces-3.3.1.jar:]
    at org.primefaces.component.layout.LayoutUnitRenderer.encodeEnd(LayoutUnitRenderer.java:51) [primefaces-3.3.1.jar:]
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1786) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_04]
Run Code Online (Sandbox Code Playgroud)

无法找到该ID.嗯....我基本上复制了RichFaces的结构.删除或编辑行的行按钮不需要:employee-form:...前缀.我想知道为什么.

给表单一个ID并在PF组件引用前加上':'语法时,代码按预期运行:

    <h:form id="employee-form">
        <p:dataTable ...>
            ...
            <p:column>
                <h:panelGrid ...>
                    <p:commandButton ...
                                     update=":employee-form:employee-remove-dialog"
                                     ...>
                        ...
                    </p:commandButton>
                </h:panelGrid>
            </p:column>
        </p:dataTable>
        <p:dialog ...
                  id="employee-remove-dialog">
        </p:dialog>
    </h:form>
Run Code Online (Sandbox Code Playgroud)

问:

为什么ap:datatable需要在根JSF ID前加上?也许这是我的代码,但发布的示例对我来说似乎很少.在任何情况下,使用它将导致整个应用程序可能存在长ID.

我究竟做错了什么?

PS:我在JBoss AS 7.1.1.Final,Mojarra 2.1.7,PF 3.3.1

Bal*_*usC 13

PrimeFaces使用提供的标准JSF算法按UIComponent#findComponent()给定的客户端ID查找组件.该算法在前面提到的javadoc中有详细描述.这是相关的摘录:

搜索表达式由任一的标识符(其精确匹配对的id属性UIComponent,或一系列由链接这样的标识符的UINamingContainer#getSeparatorChar字符值.该搜索算法应该如下操作,尽管替代算法的可被使用,只要该最终结果是一样的:

  • UIComponent通过在满足以下条件之一时立即停止,确定将成为搜索的基础:
    • 如果搜索表达式以分隔符开头(称为"绝对"搜索表达式),则基数将是UIComponent组件树的根.将剥离前导分隔符,并将搜索表达式的其余部分视为"相对"搜索表达式,如下所述.
    • 否则,如果这UIComponent是一个NamingContainer它将作为基础.
    • 否则,搜索此组件的父级.如果NamingContainer遇到a,它将成为基础.
    • 否则(如果没有NamingContainer遇到),root UIComponent将成为基础.
  • 搜索表达式(可能在上一步中修改)现在是一个"相对"搜索表达式,用于在基本组件的范围内定位具有匹配id的组件(如果有).比赛按如下方式进行:
    • 如果搜索表达式是一个简单的标识符,则将此值与id属性进行比较,然后递归通过基础的facets和子项UIComponent(除非NamingContainer找到后代,否则不搜索其自己的facet和子项).
    • 如果搜索表达式包含由分隔符分隔的多个标识符,则第一个标识符用于NamingContainer通过上一个项目符号点中的规则定位a .然后,将调用findComponent()此方法NamingContainer,传递搜索表达式的其余部分.

RichFaces使用相同的算法"有一些额外的例外".

"reRender"使用UIComponent.findComponent()算法(带有一些额外的例外)来查找组件树中的组件.

这些额外的例外没有详细描述,但众所周知,相关组件ID(即那些不以其开头的:)不仅在最近的父节点的上下文中搜索NamingContainer,而且NamingContainer在同一视图中的所有其他组件中搜索(这是顺便说一句相对昂贵的工作).

  • (+1)感谢您发布算法:对于具体案例而言,这比具体案件更具有帮助性. (3认同)