Comprender el proceso / actualización de PrimeFaces y los atributos JSF f: ajax execute / render

193

¿Qué son exactamente processy updateen los p:commandXxxcomponentes de PrimeFaces executey renderen la f:ajaxetiqueta?

¿Qué funciona en el momento de la validación? ¿Qué hace el updateatributo en lugar de actualizar el valor al componente desde el back-end? ¿El processvalor de enlace de atributo al modelo? ¿Qué es exactamente lo que @this, @parent, @ally @formen ambos atributos?

El siguiente ejemplo funciona bien, pero estoy un poco confundido con los conceptos básicos.

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />
Shardendu
fuente

Respuestas:

306

<p:commandXxx process> <p:ajax process> <f:ajax execute>

El processatributo es del lado del servidor y solo puede afectar UIComponentla implementación de s EditableValueHolder(campos de entrada) o ActionSource(campos de comando). El processatributo le dice a JSF, usando una lista separada por espacios de ID de clientes, qué componentes deben procesarse exactamente a través de todo el ciclo de vida de JSF al enviar el formulario (parcial).

JSF luego aplicará los valores de solicitud (encontrando el parámetro de solicitud HTTP basado en la propia ID de cliente del componente y luego configurándolo como valor enviado en caso de EditableValueHoldercomponentes o colocando en cola uno nuevo ActionEventen caso de ActionSourcecomponentes), realizará la conversión, validación y actualización de los valores del modelo ( EditableValueHoldersolo componentes) y finalmente invocar los en cola ActionEvent( ActionSourcesolo componentes). JSF omitirá el procesamiento de todos los demás componentes que no están cubiertos por el processatributo. Además, los componentes cuyo renderedatributo se evalúa falsedurante la fase de solicitud de valores de solicitud también se omitirán como parte de la protección contra solicitudes alteradas.

Tenga en cuenta que, en el caso de los ActionSourcecomponentes (como <p:commandButton>), es muy importante que también incluya el componente en sí en el processatributo, especialmente si tiene la intención de invocar la acción asociada con el componente. Entonces, el siguiente ejemplo que intenta procesar solo ciertos componentes de entrada cuando se invoca un cierto componente de comando no funcionará:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="foo" action="#{bean.action}" />

Solo procesaría el #{bean.foo}y no el #{bean.action}. Debería incluir también el componente de comando:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="@this foo" action="#{bean.action}" />

O, como aparentemente descubrió, usar @parentsi resultan ser los únicos componentes que tienen un padre común:

<p:panel><!-- Type doesn't matter, as long as it's a common parent. -->
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@parent" action="#{bean.action}" />
</p:panel>

O, si ambos son los únicos componentes del UIFormcomponente principal , entonces también puede usar @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@form" action="#{bean.action}" />
</h:form>

Esto a veces no es deseable si el formulario contiene más componentes de entrada que le gustaría omitir en el procesamiento, más a menudo en los casos en que desea actualizar otro (s) componente (s) de entrada o alguna sección de IU basada en el componente de entrada actual en Un método de escucha ajax. Es decir, no desea que los errores de validación en otros componentes de entrada impidan que se ejecute el método de escucha ajax.

Luego está el @all. Esto no tiene ningún efecto especial en el processatributo, sino solo en el updateatributo. A se process="@all"comporta exactamente igual que process="@form". HTML no admite el envío de múltiples formularios a la vez de todos modos.

Por cierto, también @nonepuede ser útil en caso de que no necesite procesar nada, pero solo desee actualizar algunas partes específicas a través de update, particularmente aquellas secciones cuyo contenido no depende de valores enviados o escuchas de acción.

Se debe tener en cuenta que el processatributo no tiene influencia en la carga útil de la solicitud HTTP (la cantidad de parámetros de la solicitud). Es decir, el comportamiento HTML predeterminado de enviar "todo" contenido dentro de la representación HTML del <h:form>no se verá afectado. En caso de que tenga un formulario grande y desee reducir la carga útil de la solicitud HTTP a solo estos absolutamente necesarios en el procesamiento, es decir, solo estos cubiertos por el processatributo, puede establecer el partialSubmitatributo en los componentes de PrimeFaces Ajax como en <p:commandXxx ... partialSubmit="true">o <p:ajax ... partialSubmit="true">. También puede configurar esto 'globalmente' editando web.xmly agregando

<context-param>
    <param-name>primefaces.SUBMIT</param-name>
    <param-value>partial</param-value>
</context-param>

Alternativamente, también puede usar <o:form>OmniFaces 3.0+ que por defecto es este comportamiento.

El JSF estándar equivalente al PrimeFaces específico processes executede <f:ajax execute>. Se comporta exactamente igual, excepto que no admite una cadena separada por comas, mientras que la de PrimeFaces sí (aunque personalmente recomiendo seguir la convención separada por espacios), ni la @parentpalabra clave. Además, puede ser útil saber que el valor <p:commandXxx process>predeterminado es @formwhile <p:ajax process>y el valor <f:ajax execute>predeterminado es @this. Finalmente, también es útil saber que es processcompatible con los denominados "Selectores PrimeFaces", vea también ¿Cómo funcionan los Selectores PrimeFaces como en update = "@ (. MyClass)"?


<p:commandXxx update> <p:ajax update> <f:ajax render>

El updateatributo es del lado del cliente y puede afectar la representación HTML de todos los UIComponents. El updateatributo le dice a JavaScript (el responsable de manejar la solicitud / respuesta ajax), usando una lista separada por espacios de ID de clientes, qué partes del árbol DOM de HTML deben actualizarse como respuesta al envío del formulario.

JSF luego preparará la respuesta ajax correcta para eso, conteniendo solo las partes solicitadas para actualizar. JSF omitirá todos los demás componentes que no están cubiertos por el updateatributo en la respuesta ajax, manteniendo así la carga útil de respuesta pequeña. Además, se omitirán los componentes cuyo renderedatributo se evalúe falsedurante la fase de respuesta de representación. Tenga en cuenta que aunque volvería true, JavaScript no puede actualizarlo en el árbol DOM de HTML si fue inicialmente false. Tendría que envolverlo o actualizar su padre en su lugar. Consulte también la actualización / renderización de Ajax no funciona en un componente que tiene atributo renderizado .

Por lo general, le gustaría actualizar solo los componentes que realmente necesitan ser "actualizados" en el lado del cliente al enviar el formulario (parcial). El siguiente ejemplo actualiza todo el formulario principal a través de @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@form" />
</h:form>

(tenga en cuenta que el processatributo se omite porque @formya está predeterminado )

Si bien eso puede funcionar bien, la actualización de los componentes de entrada y comando es innecesaria en este ejemplo particular. A menos que cambie los valores del modelo fooy el método barinterno action(que a su vez no sería intuitivo en la perspectiva UX), no tiene sentido actualizarlos. Los componentes del mensaje son los únicos que realmente necesitan actualizarse:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="foo_m bar_m" />
</h:form>

Sin embargo, eso se vuelve tedioso cuando tienes muchos de ellos. Esa es una de las razones por las cuales existen los Selectores PrimeFaces. Esos componentes de mensaje tienen en la salida HTML generada una clase de estilo común de ui-message, por lo que lo siguiente también debería hacer:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@(.ui-message)" />
</h:form>

(tenga en cuenta que debe mantener las ID en los componentes del mensaje, de lo contrario @(...)no funcionará. Nuevamente, vea ¿Cómo funcionan los selectores PrimeFaces como en update = "@ (. myClass)"? para más detalles)

El @parentactualiza sólo el componente principal, que por lo tanto cubre el componente de corriente y todos los hermanos y sus hijos. Esto es más útil si ha separado el formulario en grupos sanos con cada uno bajo su propia responsabilidad. Las @thisactualizaciones, obviamente, solo el componente actual. Normalmente, esto solo es necesario cuando necesita cambiar uno de los atributos HTML del componente en el método de acción. P.ej

<p:commandButton action="#{bean.action}" update="@this" 
    oncomplete="doSomething('#{bean.value}')" />

Imagine que la oncompletenecesidad de trabajar con la valueque se cambia action, entonces esta construcción no habría funcionado si el componente no se actualiza, por la sencilla razón de que oncompletees parte de la salida HTML generada (y, por lo tanto, se evalúan todas las expresiones EL allí) durante la respuesta de render).

El @allactualiza todo el documento, que debe ser usado con cuidado. Normalmente, le gustaría utilizar una verdadera solicitud GET para esto, ya sea mediante un enlace simple ( <a>o <h:link>) o una redirección después de POST por ?faces-redirect=trueo ExternalContext#redirect(). En efecto, process="@form" update="@all"tiene exactamente el mismo efecto que un envío no ajax (no parcial). En toda mi carrera en JSF, el único caso de uso sensible que encontré @alles mostrar una página de error en su totalidad en caso de que ocurra una excepción durante una solicitud de ajax. Consulte también ¿Cuál es la forma correcta de manejar las excepciones JSF 2.0 para componentes AJAXified?

El JSF estándar equivalente al PrimeFaces específico updatees renderde <f:ajax render>. Se comporta exactamente igual, excepto que no admite una cadena separada por comas, mientras que la de PrimeFaces sí (aunque personalmente recomiendo seguir la convención separada por espacios), ni la @parentpalabra clave. Ambos updatey por renderdefecto @none(que es "nada").


Ver también:

BalusC
fuente
Cuando uso update = "", la propiedad administrada del bean de respaldo no se establece y mi rutina @PostConstruct falla. ¿Alguna idea? EDITAR: • Si confía en que una propiedad administrada de # {param} esté presente en las solicitudes POST posteriores, entonces debe incluirla como <f: param> en los componentes de UICommand.
K.Nicholas
puede que un proceso / actualización de un panelGroup procese / actualice el contenido de este panelGroup, por ejemplo: <h: panelGroup id = "pgId"> // los textos de entrada van aquí <h: panelGroup> <p: commandLink process = "pgId" update = "pgId" />
bob-cac
Thx @BalusC por esta muy buena explicación!
ProgrammingIsAwsome
2
@Rapster: porque processno está configurado, por lo que utiliza el valor predeterminado de @form. Esto también se explica en la respuesta anterior.
BalusC
2
@Roland: está ocultando un problema diferente y más grave con la configuración de la aplicación.
BalusC
54

Si tiene dificultades para recordar los valores predeterminados (sé que tengo ...) aquí hay un breve extracto de la respuesta de BalusC:

Componente | Enviar | Actualizar
------------ | --------------- | --------------
f: ajax | ejecutar = "@ esto" | render = "@ none"
p: ajax | proceso = "@ this" | actualización = "@ ninguno"
p: comandoXXX | proceso = "@ formulario" | actualización = "@ ninguno"
Jaqen H'ghar
fuente
Solo una pequeña corrección: el valor predeterminado de processfor p:commandXXXes @all. Además, esto parece aplicarse a todos los componentes compatibles con AJAX, como p:menuitem.
Stephan Rauh
1
Hola @StephanRauh, muchas gracias por comentar. ¿Dónde leíste el valor predeterminado @all? Por lo que puedo leer de la respuesta de BalusC @form, @alles equivalente al @formproceso. Buen punto sobre los otros componentes, supongo que tendrá que buscar en el código fuente cuando el tiempo para ver qué componentes se aplica, como me gustaría algo más que escribir no estar equivocado
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko me contó sobre la @allparte. Debe saber que ha implementado recientemente el motor AJAX de PrimeFaces recientemente. Más tarde, lo verifiqué dos veces, pero leí el código fuente de PrimeFaces y miré las solicitudes de XHR. Espero haberlo hecho bien esta vez porque he implementado las solicitudes AJAX de BootsFaces para que funcionen de manera idéntica a las solicitudes AJAX de PrimeFaces.
Stephan Rauh
Sería engañoso decir que el valor predeterminado es @todos cuando HTML no admite el envío de múltiples formularios. Los desarrolladores necesitan conocer el valor predeterminado efectivo (por lo que Thomas podría cambiarlo en consecuencia). Por cierto, estos valores predeterminados se definen incorrectamente como nulos en la Guía del usuario de Primefaces 6.2.
Marc Dzaebel el
27

Por proceso (en la especificación JSF se llama ejecutar), le dice a JSF que limite el procesamiento a los componentes que se especifican, todo lo demás se ignora.

actualización indica qué elemento se actualizará cuando el servidor responda a su solicitud.

@todos : cada componente se procesa / procesa.

@this : el componente solicitante con el atributo execute se procesa / procesa.

@form : El formulario que contiene el componente solicitante se procesa / procesa.

@parent : el padre que contiene el componente solicitante se procesa / procesa.

Con Primefaces, incluso puede usar selectores JQuery, consulte este blog: http://blog.primefaces.org/?p=1867

faissalb
fuente
2

Tenga en cuenta que PrimeFaces admite las palabras clave JSF 2.0+ estándar:

  • @this Componente actual.
  • @all Vista completa
  • @form Forma ancestral más cercana del componente actual.
  • @none Sin componente

y las palabras clave estándar JSF 2.3+:

  • @child(n) Enésimo niño.
  • @composite Componente compuesto más cercano ancestro.
  • @id(id) Se usa para buscar componentes por su identificación, ignorando la estructura de árbol de componentes y nombrando contenedores.
  • @namingcontainer El contenedor de nombres de antepasados ​​más cercano del componente actual.
  • @parent Padre del componente actual.
  • @previous Hermano anterior.
  • @next Proximo hermano.
  • @root La instancia UIViewRoot de la vista se puede usar para comenzar a buscar desde la raíz en lugar del componente actual.

Pero, también viene con algunas palabras clave específicas de PrimeFaces:

  • @row(n) enésima fila
  • @widgetVar(name) Componente con widgetVar dado.

E incluso puede usar algo llamado "PrimeFaces Selectors" que le permite usar jQuery Selector API. Por ejemplo, para procesar todas las entradas en un elemento con la clase CSS myClass:

process="@(.myClass :input)"

Ver:

Jasper de Vries
fuente
2
Tenga en cuenta que incluso JSF2.3 + admite la mayoría de las palabras clave.
tandraschko