2012-08-07 12 views
6

estoy empezando con PrimeFaces 3.3.1 viene de RichFaces 3 y 4.PrimeFaces/JSF componente de identificación que no se encuentran dentro de p: tabla de datos

Tengo una tabla de datos con la estructura:

  <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> 

sin embargo PrimeFaces se emite una excepción:

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] 

La identificación no puede ser encontrado. Hmm ... Básicamente copié la estructura de RichFaces. Allí, el botón de la fila para eliminar o editar la fila no necesita el: employee-form: ... prefixing. Me pregunto por qué.

Al dar forma un ID y prefijar las referencias de componentes PF con el ':' la sintaxis del código se ejecuta como se esperaba:

<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> 

Q:

¿Por qué AP: tabla de datos necesidad para prefijar los ID raíz JSF? Tal vez es mi código, pero el ejemplo publicado parece mínimo para mí. En cualquier caso, usar esto dará como resultado identificaciones posiblemente largas en toda la aplicación.

¿Qué estoy haciendo mal?

PS: Estoy en JBoss AS 7.1.1.Final, Mojarra 2.1.7, 3.3.1 PF

Respuesta

13

PrimeFaces utiliza el algoritmo de JSF estándar suministrado por UIComponent#findComponent() para encontrar componentes de un ID de cliente determinado. El algoritmo se describe en detalle en el javadoc antes mencionado. Aquí está un extracto de relevancia:.

Una expresión búsqueda se compone de un identificador (que se corresponde exactamente contra la propiedad id de un UIComponent, o una serie de tales identificadores vinculados por el valor UINamingContainer#getSeparatorChar carácter La búsqueda algoritmo debe funciona como sigue, aunque alogrithms alternativas pueden ser utilizados siempre que el resultado final es el mismo:

  • Identificar el UIComponent que será la base para la búsqueda, al detener tan pronto como una de las condiciones siguientes es conocido:
    • Si la expresión de búsqueda comienza con el carácter separador (llamado expresión de búsqueda "absoluta"), la base será la raíz UIComponent del árbol de componentes. El carácter separador principal se eliminará y el resto de la expresión de búsqueda se tratará como una expresión de búsqueda "relativa" como se describe a continuación.
    • De lo contrario, si este UIComponent es un NamingContainer, servirá de base.
    • De lo contrario, busque los padres de este componente. Si se encuentra un NamingContainer, será la base.
    • En caso contrario (si no se encuentra NamingContainer), la raíz será UIComponent.
  • La expresión de búsqueda (posiblemente modificada en el paso anterior) ahora es una expresión de búsqueda "relativa" que se utilizará para ubicar el componente (si lo hay) que tenga una identificación que coincida, dentro del alcance de la base componente. El partido se lleva a cabo de la siguiente manera:
    • Si la expresión de búsqueda es un identificador sencillo, este valor se compara con la propiedad id, y luego de forma recursiva a través de las facetas y los niños de la base UIComponent (excepto que si un descendiente NamingContainer es encontrado, sus propias facetas e hijos no son buscados).
    • Si la expresión de búsqueda incluye más de un identificador separado por el carácter separador, el primer identificador se usa para ubicar un NamingContainer según las reglas en el punto anterior. Luego, se llamará al método findComponent() de este NamingContainer, pasando el resto de la expresión de búsqueda.

RichFaces utiliza el mismo algoritmo "with some additional exceptions".

"reRender" utiliza UIComponent.findComponent() algoritmo (con algunas excepciones adicionales) para encontrar el componente en el árbol de componentes.

Esas excepciones adicionales son la nada en detalle descrito, pero es bien sabido que los identificadores relativos de los componentes (es decir, aquellos que no empiezan con :) no sólo se buscan en el contexto de los padres más cercano NamingContainer, sino también en todos los demás NamingContainer componentes en la misma vista (que es un trabajo relativamente caro por cierto).

+3

(+1) Gracias por publicar el algoritmo: eso es mucho más útil que un hormigón para una caja de hormigón. – Ralph

Cuestiones relacionadas