update ajax jsf jsf-2 primefaces clientid

update - render jsf ajax



¿Cómo averiguar la identificación del cliente del componente para la actualización/renderización de Ajax? No se puede encontrar el componente con la expresión "foo" a la que se hace referencia desde "barra" (4)

Busque en el resultado HTML la identificación del cliente real

Debe buscar en el resultado HTML generado para encontrar el ID de cliente correcto. Abra la página en el navegador, haga clic con el botón derecho y Ver origen . Ubique la representación HTML del componente de interés JSF y tome su id como ID de cliente. Puede usarlo de forma absoluta o relativa dependiendo del contenedor de nombres actual. Ver el siguiente capítulo.

Nota: si contiene un índice de iteración como :0: , :1: etc. (porque está dentro de un componente iterativo), entonces debe darse cuenta de que no siempre es posible actualizar una iteración específica. Ver la parte inferior de la respuesta para más detalles sobre eso.

Memorice los componentes de NamingContainer y siempre proporcione una identificación fija

Si un componente al que le gustaría hacer referencia mediante ajax process / execute / update / render está dentro del mismo padre NamingContainer , simplemente haga referencia a su propia identificación.

<h:form id="form"> <p:commandLink update="result"> <!-- OK! --> <h:panelGroup id="result" /> </h:form>

Si no está dentro del mismo NamingContainer , entonces necesita referenciarlo usando un ID de cliente absoluto. Un ID de cliente absoluto comienza con el NamingContainer separador NamingContainer , que es por defecto :

<h:form id="form"> <p:commandLink update="result"> <!-- FAIL! --> </h:form> <h:panelGroup id="result" />

<h:form id="form"> <p:commandLink update=":result"> <!-- OK! --> </h:form> <h:panelGroup id="result" />

<h:form id="form"> <p:commandLink update=":result"> <!-- FAIL! --> </h:form> <h:form id="otherform"> <h:panelGroup id="result" /> </h:form>

<h:form id="form"> <p:commandLink update=":otherform:result"> <!-- OK! --> </h:form> <h:form id="otherform"> <h:panelGroup id="result" /> </h:form>

NamingContainer componentes de NamingContainer son, por ejemplo, <h:form> , <h:dataTable> , <p:tabView> , <cc:implementation> (por lo tanto, todos los componentes compuestos), etc. Los reconoce fácilmente mirando la salida HTML generada, su identificación será antepuesta a la identificación del cliente generado de todos los componentes secundarios. Tenga en cuenta que cuando no tienen una ID fija, JSF usará una ID autogenerada en el formato j_idXXX . Debes evitarlo por completo dándoles una identificación fija. El OmniFaces NoAutoGeneratedIdViewHandler puede ser útil en esto durante el desarrollo.

Si sabe encontrar el javadoc del UIComponent en cuestión, entonces también puede verificar allí si implementa la interfaz de NamingContainer o no. Por ejemplo, HtmlForm (el UIComponent detrás de la etiqueta <h:form> ) muestra que implementa NamingContainer , pero HtmlPanelGroup (el UIComponent detrás de la etiqueta <h:panelGroup> ) no lo muestra, por lo que no implementa NamingContainer . Aquí está el javadoc de todos los componentes estándar y aquí está el javadoc de PrimeFaces .

Resolviendo su problema

Entonces en tu caso de:

<p:tabView id="tabs"><!-- This is a NamingContainer --> <p:tab id="search"><!-- This is NOT a NamingContainer --> <h:form id="insTable"><!-- This is a NamingContainer --> <p:dialog id="dlg"><!-- This is NOT a NamingContainer --> <h:panelGrid id="display">

El resultado HTML generado de <h:panelGrid id="display"> ve así:

<table id="tabs:insTable:display">

Necesitas tomar exactamente esa id como ID de cliente y luego prefijar : para usar en la update :

<p:commandLink update=":tabs:insTable:display">

Las referencias externas incluyen / tagfile / composite

Si este enlace de comando está dentro de un include / tagfile, y el destino está fuera de él, y por lo tanto no conoce necesariamente el ID del contenedor padre de nombres del contenedor de nombres actual, entonces puede hacer una referencia dinámica a través de UIComponent#getNamingContainer() como así:

<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">

O bien, si este enlace de comando está dentro de un componente compuesto y el objetivo está fuera de él:

<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">

O bien, si tanto el enlace de comando como el destino están dentro del mismo componente compuesto:

<p:commandLink update=":#{cc.clientId}:display">

Consulte también Obtener id del contenedor de nombres padre en la plantilla para atributo de renderizado / actualización

¿Cómo funciona bajo las sábanas?

Todo esto se especifica como "expresión de búsqueda" en el javadoc UIComponent#findComponent() :

Una expresión de búsqueda consiste en un identificador (que coincide exactamente con la propiedad id de un UIComponent , o una serie de identificadores vinculados por el valor del carácter UINamingContainer#getSeparatorChar . El algoritmo de búsqueda debe funcionar de la siguiente manera, aunque pueden utilizarse alogritos alternativos siempre que el resultado final sea el mismo:

  • Identifique el UIComponent que será la base para la búsqueda, deteniéndose tan pronto como se cumpla una de las siguientes condiciones:
    • Si la expresión de búsqueda comienza con el carácter separador (llamado expresión de búsqueda "absoluta"), la base será el UIComponent raíz 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á como base.
    • De lo contrario, busque los padres de este componente. Si se encuentra un NamingContainer , será la base.
    • De lo contrario (si no se encuentra NamingContainer ), el UIComponent raíz será la base.
  • 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 tiene un ID que coincida, dentro del alcance del componente base. La coincidencia se realiza de la siguiente manera:
    • Si la expresión de búsqueda es un identificador simple, este valor se compara con la propiedad id y recursivamente a través de las facetas e hijos del UIComponent base (excepto que si se encuentra un NamingContainer descendiente, sus propias facetas e hijos no se buscan).
    • 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 por las reglas en el punto anterior. Luego, se findComponent() método findComponent() de este NamingContainer , pasando el resto de la expresión de búsqueda.

Tenga en cuenta que PrimeFaces también se adhiere a la especificación JSF, pero RichFaces utiliza "algunas excepciones adicionales" .

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

Esas excepciones adicionales no se describen en detalle en ninguna parte, pero se sabe que los identificadores de componentes relativos (es decir, aquellos que no comienzan con NamingContainer no solo se buscan en el contexto del NamingContainer primario más NamingContainer , sino también en todos los demás componentes de NamingContainer en la misma vista (que es un trabajo relativamente caro por cierto).

Nunca use prependId="false"

Si todo esto aún no funciona, entonces verifique si no está utilizando <h:form prependId="false"> . Esto fallará durante el procesamiento del ajax submit y render. Véase también esta pregunta relacionada: UIForm con prependId = "false" rompe <f: ajax render> .

Hacer referencia a una ronda de iteración específica de componentes iterativos

<h:dataTable> mucho tiempo, no fue posible hacer referencia a un elemento iterado específico al iterar componentes como <ui:repeat> y <h:dataTable> así:

<h:form id="form"> <ui:repeat id="list" value="#{[''one'',''two'',''three'']}" var="item"> <h:outputText id="item" value="#{item}" /><br/> </ui:repeat> <h:commandButton value="Update second item"> <f:ajax render=":form:list:1:item" /> </h:commandButton> </h:form>

Sin embargo, desde Mojarra 2.2.5, <f:ajax> comenzó a admitirlo (simplemente dejó de validarlo, por lo que nunca más se enfrentaría a la excepción en la pregunta mencionada, se planea otra corrección de mejora para más adelante).

Esto no funciona aún en las versiones actuales de MyFaces 2.2.7 y PrimeFaces 5.2. El soporte podría venir en las versiones futuras. Mientras tanto, la mejor opción es actualizar el componente de iteración en sí, o un elemento principal en caso de que no represente HTML, como <ui:repeat> .

Al utilizar PrimeFaces, considere Buscar Expresiones o Selectores

PrimeFaces Search Expressions le permite hacer referencia a los componentes a través de expresiones de búsqueda de árbol de componentes JSF. JSF tiene varios integrados:

  • @this : componente actual
  • @form : UIForm padre
  • @all : documento completo
  • @none : nada

PrimeFaces ha mejorado esto con nuevas palabras clave y soporte de expresión compuesta:

  • @parent : componente principal
  • @namingcontainer : parent UINamingContainer
  • @widgetVar(name) : componente identificado por determinado widgetVar

También puede mezclar esas palabras clave en expresiones compuestas como @form:@parent , @this:@parent:@parent , etc.

PrimeFaces Selectors (PFS) como en @(.someclass) permite hacer referencia a los componentes a través de la sintaxis del selector jQuery CSS. Por ejemplo, hacer referencia a los componentes que tienen toda una clase de estilo común en el resultado HTML. Esto es particularmente útil en caso de que necesite hacer referencia a "muchos" componentes. Esto solo requiere de antemano que los componentes de destino tengan todo un ID de cliente en la salida HTML (fijo o autogenerado, no importa). Consulte también ¿Cómo funcionan los selectores PrimeFaces en update = "@ (. MyClass)"?

El siguiente código está inspirado en PrimeFaces DataGrid + DataTable Tutorials y puesto en un <p:tab> de un <p:tabView> reside en un <p:layoutUnit> de un <p:layout> . Aquí está la parte interna del código (comenzando desde el componente p:tab ); la parte externa es trivial.

<p:tabView id="tabs"> <p:tab id="search" title="Search"> <h:form id="insTable"> <p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}"> <p:column> <p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()"> <f:setPropertyActionListener value="#{lndInstrument}" target="#{instrumentBean.selectedInstrument}" /> <h:outputText value="#{lndInstrument.name}" /> </p:commandLink> </p:column> </p:dataTable> <p:dialog id="dlg" modal="true" widgetVar="dlg"> <h:panelGrid id="display"> <h:outputText value="Name:" /> <h:outputText value="#{instrumentBean.selectedInstrument.name}" /> </h:panelGrid> </p:dialog> </h:form> </p:tab> </p:tabView>

Cuando hago clic en <p:commandLink> , el código deja de funcionar y muestra el mensaje:

No se puede encontrar el componente con la expresión "insTable: display" a la que se hace referencia desde "tabulaciones: insTable: select".

Cuando intento lo mismo con <f:ajax> , falla con un mensaje diferente que básicamente dice lo mismo:

<f:ajax> contiene un ID desconocido "insTable: display" no puede ubicarlo en el contexto de las pestañas del componente ": insTable: select"

¿Cómo es esto causado y cómo puedo resolverlo?


Es porque la pestaña también es un contenedor de nombres ... tu actualización debe ser update="Search:insTable:display" Lo que puedes hacer también es simplemente colocar tu diálogo fuera del formulario y aún dentro de la pestaña, entonces sería: update="Search:display"


Pruebe change update="insTable:display" para update="display" . Creo que no puede prefijar el ID con el ID de formulario así.


antes que nada: por lo que sé que colocar el diálogo dentro de una pestaña es una mala práctica ... es mejor que lo saques ...

y ahora a tu pregunta:

lo siento, me tomó algo de tiempo para obtener lo que exactamente quería implementar,

lo hice en mi aplicación web solo ahora, y funciona

como he dicho antes, coloque el p: dialogar al costado del `p: tabView,

deje el diálogo p: como inicialmente sugirió:

<p:dialog modal="true" widgetVar="dlg"> <h:panelGrid id="display"> <h:outputText value="Name:" /> <h:outputText value="#{instrumentBean.selectedInstrument.name}" /> </h:panelGrid> </p:dialog>

y el p: commandlink debería verse así (todo lo que hice fue cambiar el atributo de actualización)

<p:commandLink update="display" oncomplete="dlg.show()"> <f:setPropertyActionListener value="#{lndInstrument}" target="#{instrumentBean.selectedInstrument}" /> <h:outputText value="#{lndInstrument.name}" /> </p:commandLink>

lo mismo funciona en mi aplicación web, y si no funciona para usted, entonces supongo que hay algo mal en su código de Java Bean ...