2012-08-07 3 views
6

Sto iniziando con primefaces 3.3.1 venuta fuori RichFaces 3 e 4.primefaces/JSF ID componente non trovato all'interno di p: DataTable

Ho un DataTable con la struttura:

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

Tuttavia primefaces genera un'eccezione:

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] 

L'ID non può essere trovato. Hmm .... Ho praticamente copiato la struttura da RichFaces. Lì il pulsante di riga per cancellare o modificare la riga non ha bisogno del: modulo-dipendente: ... prefisso. Mi chiedo perché.

Nel dare la forma di un ID e anteponendo i riferimenti dei componenti PF con il ':' la sintassi del codice viene eseguito come previsto:

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

D:

Perché ap: DataTable necessità prefisso gli ID JSF di root? Forse è il mio codice, ma l'esempio pubblicato mi sembra minimale. In ogni caso, l'utilizzo di questo comporterà probabilmente lunghi ID in tutta l'applicazione.

Cosa sto sbagliando?

PS: Sono su JBoss AS 7.1.1.Final, Mojarra 2.1.7, 3.3.1 PF

risposta

13

primefaces utilizza l'algoritmo JSF standard fornito da UIComponent#findComponent() di trovare i componenti di un dato ID cliente. L'algoritmo è descritto in dettaglio nel javadoc aforelinked. Ecco un estratto di rilevanza:.

Un'espressione ricerca costituito da un identificatore (che è compensata esattamente contro la proprietà ID di un UIComponent, o una serie di tali identificatori legati dal valore UINamingContainer#getSeparatorChar carattere La ricerca algoritmo dovrebbe opera come segue, se alogrithms alternativi possono essere usati fintanto che il risultato finale è lo stesso:

  • Identificare il UIComponent che sarà la base per la ricerca, fermando non appena una delle seguenti condizioni incontrato:
  • Se l'espressione di ricerca inizia con il carattere separatore (definito un'espressione di ricerca "assoluta"), la base sarà la radice UIComponent dell'albero dei componenti. Il carattere di separazione iniziale verrà rimosso e il resto dell'espressione di ricerca verrà trattato come un'espressione di ricerca "relativa" come descritto di seguito.
  • Altrimenti, se questo UIComponent è un NamingContainer servirà come base.
  • Altrimenti, cerca tra i genitori di questo componente. Se si incontra uno NamingContainer, sarà la base.
  • In caso contrario (se viene rilevato il numero NamingContainer), la radice UIComponent sarà la base.
  • L'espressione di ricerca (eventualmente modificata nel passaggio precedente) è ora un'espressione di ricerca "relativa" che verrà utilizzata per individuare il componente (se presente) che ha un ID corrispondente, nell'ambito della base componente. La partita viene eseguita come segue:
    • Se l'espressione di ricerca è un semplice identificatore, questo valore viene confrontato con la proprietà ID, e quindi in modo ricorsivo attraverso le sfaccettature ei bambini della base UIComponent (tranne che se un discendente NamingContainer è trovato, le sue sfaccettature ei bambini non vengono cercati).
    • Se l'espressione di ricerca include più di un identificatore separato dal carattere separatore, il primo identificatore viene utilizzato per individuare uno NamingContainer dalle regole nel punto elenco precedente. Quindi, verrà chiamato il metodo findComponent() di questo NamingContainer, passando il resto dell'espressione di ricerca.

RichFaces utilizza lo stesso algoritmo "with some additional exceptions".

"rerender" utilizza UIComponent.findComponent() algoritmo (con alcune eccezioni supplementari) per trovare il componente nell'albero componente.

Quelle ulteriori eccezioni sono in nessun posto in dettaglio descritto, ma è ben noto che gli ID dei componenti relativi (cioè quelli che non inizia con :) non solo sono cercata nel contesto del genitore più vicino NamingContainer, ma anche in tutti gli altri NamingContainer componenti nella stessa vista (che è un lavoro relativamente costoso tra l'altro).

+3

(+1) Grazie per aver pubblicato l'algoritmo: questo è molto più utile di un concreto per un caso concreto. – Ralph