Comprendre les attributs PrimeFaces Process / Update et JSF f: ajax execute / render

195

Que sont exactement processet updatedans les p:commandXxxcomposants PrimeFaces et executeet renderdans la f:ajaxbalise?

Qui fonctionne au moment de la validation? Que fait l' updateattribut plutôt que de mettre à jour la valeur en composant à partir du back-end? L' processattribut lie-t-il la valeur au modèle? Que faire exactement @this, @parent, @allet @formdans les deux attributs?

L'exemple ci-dessous fonctionne bien, mais je suis un peu confus dans les concepts de base.

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

Réponses:

308

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

L' processattribut est côté serveur et ne peut affecter que l' UIComponentimplémentation EditableValueHolder(champs de saisie) ou ActionSource(champs de commande). L' processattribut indique à JSF, à l'aide d'une liste d'ID client séparés par des espaces, quels composants doivent être traités exactement tout au long du cycle de vie JSF lors de la soumission (partielle) du formulaire.

JSF appliquera ensuite les valeurs de la requête (recherche du paramètre de requête HTTP en fonction de l'ID client du composant, puis le définissant comme valeur soumise dans le cas des EditableValueHoldercomposants ou en mettant en file d'attente un nouveau ActionEventdans le cas des ActionSourcecomposants), effectuera la conversion, la validation et la mise à jour des valeurs du modèle ( EditableValueHoldercomposants uniquement) et enfin appeler la file d'attente ActionEvent( ActionSourcecomposants uniquement). JSF ignorera le traitement de tous les autres composants qui ne sont pas couverts par l' processattribut. De plus, les composants dont l' renderedattribut est évalué falsependant la phase d'application des valeurs de demande seront également ignorés dans le cadre de la protection contre les demandes altérées.

Notez que c'est dans le cas de ActionSourcecomposants (tels que <p:commandButton>) très importants que vous incluiez également le composant lui-même dans l' processattribut, en particulier si vous avez l'intention d'appeler l'action associée au composant. Ainsi, l'exemple ci-dessous qui vise à ne traiter que certains composants d'entrée lorsqu'un certain composant de commande est appelé ne fonctionnera pas:

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

Il ne traiterait que le #{bean.foo}et non le #{bean.action}. Vous devrez également inclure le composant de commande lui-même:

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

Ou, comme vous l'avez apparemment découvert, en utilisant @parents'ils sont les seuls composants ayant un parent commun:

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

Ou, s'ils se trouvent tous deux être les seuls composants du UIFormcomposant parent , vous pouvez également utiliser @form:

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

Cela n'est parfois pas souhaitable si le formulaire contient plus de composants d'entrée que vous souhaitez ignorer lors du traitement, plus que souvent dans les cas où vous souhaitez mettre à jour un ou plusieurs autres composants d'entrée ou une section d'interface utilisateur basée sur le composant d'entrée actuel dans une méthode d'écoute ajax. Vous ne voulez pas que des erreurs de validation sur d'autres composants d'entrée empêchent l'exécution de la méthode d'écoute ajax.

Ensuite, il y a le @all. Cela n'a aucun effet spécial dans l' processattribut, mais seulement dans l' updateattribut. A process="@all"se comporte exactement de la même manière que process="@form". De toute façon, HTML ne prend pas en charge la soumission de plusieurs formulaires à la fois.

Il y a d'ailleurs aussi un @nonequi peut être utile au cas où vous n'auriez absolument pas besoin de traiter quoi que ce soit, mais que vous ne vouliez mettre à jour que certaines parties spécifiques via update, en particulier les sections dont le contenu ne dépend pas des valeurs soumises ou des écouteurs d'action.

Il convient de noter que l' processattribut n'a aucune influence sur la charge utile de la requête HTTP (la quantité de paramètres de la requête). Cela signifie que le comportement HTML par défaut d'envoi de "tout" contenu dans la représentation HTML du <h:form>ne sera pas affecté. Si vous avez un formulaire volumineux et que vous souhaitez réduire la charge utile de la requête HTTP à ceux qui sont absolument nécessaires au traitement, c'est-à-dire uniquement ceux couverts par l' processattribut, vous pouvez définir l' partialSubmitattribut dans les composants PrimeFaces Ajax comme dans <p:commandXxx ... partialSubmit="true">ou <p:ajax ... partialSubmit="true">. Vous pouvez également configurer cela `` globalement '' en éditant web.xmlet en ajoutant

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

Vous pouvez également utiliser <o:form>OmniFaces 3.0+ qui utilise par défaut ce comportement.

L'équivalent JSF standard du spécifique PrimeFaces processest executede <f:ajax execute>. Il se comporte exactement de la même manière, sauf qu'il ne prend pas en charge une chaîne séparée par des virgules, contrairement à PrimeFaces (bien que je recommande personnellement de s'en tenir à la convention séparée par des espaces), ni le @parentmot - clé. En outre, il peut être utile de savoir que la valeur par <p:commandXxx process>défaut est @formwhile <p:ajax process>et la valeur par <f:ajax execute>défaut @this. Enfin, il est également utile de savoir que processprend en charge les soi-disant "PrimeFaces Selectors", voir aussi Comment fonctionnent les PrimeFaces Selectors comme dans update = "@ (. MyClass)"?


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

L' updateattribut est côté client et peut affecter la représentation HTML de tous les UIComponents. L' updateattribut indique à JavaScript (celui responsable de la gestion de la demande / réponse ajax), à l'aide d'une liste d'ID client séparés par des espaces, quelles parties de l'arborescence DOM HTML doivent être mises à jour en réponse à l'envoi du formulaire.

JSF préparera alors la bonne réponse ajax pour cela, contenant uniquement les parties demandées à mettre à jour. JSF ignorera tous les autres composants qui ne sont pas couverts par l' updateattribut dans la réponse ajax, gardant ainsi la charge utile de la réponse petite. De plus, les composants dont l' renderedattribut est évalué falsependant la phase de réponse de rendu seront ignorés. Notez que même s'il reviendrait true, JavaScript ne peut pas le mettre à jour dans l'arborescence DOM HTML s'il l'était initialement false. Vous auriez besoin de l'envelopper ou de mettre à jour son parent à la place. Voir aussi La mise à jour / le rendu Ajax ne fonctionne pas sur un composant qui a un attribut de rendu .

Habituellement, vous souhaitez mettre à jour uniquement les composants qui ont vraiment besoin d'être "rafraîchis" côté client lors de l'envoi (partiel) du formulaire. L'exemple ci-dessous met à jour l'ensemble du formulaire parent via @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>

(notez que l' processattribut est omis car il est @formdéjà par défaut )

Bien que cela puisse fonctionner correctement, la mise à jour des composants d'entrée et de commande est dans cet exemple particulier inutile. À moins que vous ne changiez les valeurs du modèle fooet la méthode barinterne action(ce qui à son tour ne serait pas intuitif en perspective UX), il est inutile de les mettre à jour. Les composants du message sont les seuls qui doivent vraiment être mis à jour:

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

Cependant, cela devient fastidieux lorsque vous en avez beaucoup. C'est l'une des raisons pour lesquelles les PrimeFaces Selectors existent. Ces composants de message ont dans la sortie HTML générée une classe de style commune de ui-message, donc ce qui suit devrait également faire:

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

(notez que vous devez conserver les identifiants sur les composants de message, sinon @(...)cela ne fonctionnera pas! Encore une fois, voir Comment fonctionnent les sélecteurs PrimeFaces comme dans update = "@ (. myClass)"? pour plus de détails)

Les @parentmises à jour uniquement le composant parent, qui couvre ainsi le composant actuel et tous les frères et leurs enfants. Ceci est plus utile si vous avez séparé le formulaire en groupes sains avec chacun sa propre responsabilité. Les @thismises à jour, évidemment, que le composant actuel. Normalement, cela n'est nécessaire que lorsque vous devez modifier l'un des propres attributs HTML du composant dans la méthode d'action. Par exemple

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

Imaginez que le oncompletebesoin de travailler avec le valuequi est modifié dans action, alors cette construction n'aurait pas fonctionné si le composant n'était pas mis à jour, pour la simple raison qui oncompletefait partie de la sortie HTML générée (et donc toutes les expressions EL présentes sont évaluées pendant la réponse de rendu).

Le @allmet à jour l'ensemble du document, qui doit être utilisé avec précaution. Normalement, vous aimeriez utiliser une vraie requête GET pour cela à la place soit par un simple lien ( <a>ou <h:link>), soit par une redirection après POST par ?faces-redirect=trueou ExternalContext#redirect(). En effet, process="@form" update="@all"a exactement le même effet qu'une soumission non ajax (non partielle). Dans toute ma carrière JSF, le seul cas d'utilisation raisonnable que j'ai rencontré @allest d'afficher une page d'erreur dans son intégralité au cas où une exception se produirait lors d'une requête ajax. Voir aussi Quelle est la bonne façon de traiter les exceptions JSF 2.0 pour les composants AJAXifiés?

L'équivalent JSF standard du spécifique PrimeFaces updateest renderde <f:ajax render>. Il se comporte exactement de la même manière, sauf qu'il ne prend pas en charge une chaîne séparée par des virgules, contrairement à PrimeFaces (bien que je recommande personnellement de s'en tenir à la convention séparée par des espaces), ni le @parentmot - clé. Les deux updateet prend la valeur par renderdéfaut @none(ce qui signifie «rien»).


Voir également:

BalusC
la source
Lorsque j'utilise update = "", la propriété gérée du bean de support n'est pas définie et ma routine @PostConstruct échoue. Des pensées? EDIT: • Si vous comptez qu'une propriété gérée # {param} est présente dans les requêtes POST suivantes, vous devez l'inclure en tant que <f: param> dans les composants UICommand.
K.Nicholas
peut un processus / mise à jour d'un panelGroup traiter / mettre à jour le contenu de ce panelGroup ex: <h: panelGroup id = "pgId"> // les textes d'entrée vont ici <h: panelGroup> <p: commandLink process = "pgId" update = "pgId" />
bob-cac
Merci @BalusC pour cette très belle explication!
ProgrammingIsAwsome
2
@Rapster: car processn'est pas défini, il utilise donc la valeur par défaut de @form. Ceci est également expliqué dans la réponse ci-dessus.
BalusC
2
@Roland: il cache un problème différent, plus sérieux, avec la configuration de l'application.
BalusC
54

Si vous avez du mal à vous souvenir des valeurs par défaut (je sais que j'ai ...), voici un court extrait de la réponse de BalusC:

Composant | Soumettre | Rafraîchir
------------ | --------------- | --------------
f: ajax | execute = "@ this" | render = "@ aucun"
p: ajax | process = "@ this" | update = "@ none"
p: commandXXX | process = "@ formulaire" | update = "@ none"
Jaqen H'ghar
la source
Juste une petite correction: la valeur par défaut de processfor p:commandXXXest @all. De plus, cela semble s'appliquer à tous les composants prenant en charge AJAX, tels que p:menuitem.
Stephan Rauh
1
Salut @StephanRauh, merci beaucoup pour vos commentaires. Où avez-vous lu la valeur par défaut @all? D'après ce que je peux lire dans la réponse de BalusC, il est @formcependant @alléquivalent à @formen cours. Bon point à propos des autres composants, je suppose que je devrai regarder dans le code source le moment venu pour voir à quels composants il s'applique, car je préfère ne pas écrire quelque chose qui pourrait être faux
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko m'a parlé du @allmorceau. Il doit savoir, il a ré-implémenté le moteur AJAX de PrimeFaces récemment. Plus tard, je l'ai vérifié deux fois mais en lisant le code source de PrimeFaces et en regardant les requêtes XHR. J'espère avoir bien compris cette fois car j'ai implémenté les requêtes AJAX de BootsFaces pour qu'elles fonctionnent de la même manière que les requêtes AJAX de PrimeFaces.
Stephan Rauh
Il serait trompeur de dire que la valeur par défaut est @all lorsque HTML ne prend pas en charge la soumission de plusieurs formulaires. Les développeurs doivent connaître la valeur par défaut effective (afin que Thomas puisse la modifier en conséquence). À propos, ces valeurs par défaut sont incorrectement définies comme nulles dans le Guide de l'utilisateur Primefaces 6.2.
Marc Dzaebel
27

Par processus (dans la spécification JSF, cela s'appelle execute), vous indiquez à JSF de limiter le traitement aux composants spécifiés, tout le reste est simplement ignoré.

update indique quel élément sera mis à jour lorsque le serveur répondra à votre demande.

@all : chaque composant est traité / rendu.

@this : Le composant demandeur avec l'attribut d'exécution est traité / rendu.

@form : le formulaire qui contient le composant demandeur est traité / rendu.

@parent : le parent qui contient le composant demandeur est traité / rendu.

Avec Primefaces, vous pouvez même utiliser des sélecteurs JQuery, consultez ce blog: http://blog.primefaces.org/?p=1867

faissalb
la source
2

Veuillez noter que PrimeFaces prend en charge les mots-clés standard JSF 2.0+:

  • @this Composant actuel.
  • @all Vue d'ensemble.
  • @form Forme d'ancêtre le plus proche du composant actuel.
  • @none Aucun composant.

et les mots-clés standard JSF 2.3+:

  • @child(n) nième enfant.
  • @composite Le plus proche ancêtre du composant composite.
  • @id(id) Utilisé pour rechercher des composants par leur identifiant en ignorant l'arborescence des composants et en nommant les conteneurs
  • @namingcontainer Conteneur de dénomination de l'ancêtre le plus proche du composant actuel.
  • @parent Parent du composant courant.
  • @previous Frère précédent.
  • @next Frère suivant.
  • @root UIViewRoot instance de la vue, peut être utilisée pour lancer la recherche à partir de la racine au lieu du composant actuel.

Mais, il est également livré avec des mots-clés spécifiques à PrimeFaces:

  • @row(n) nième rangée.
  • @widgetVar(name) Composant avec widgetVar donné.

Et vous pouvez même utiliser quelque chose appelé "PrimeFaces Selectors" qui vous permet d'utiliser l'API jQuery Selector. Par exemple, pour traiter toutes les entrées d'un élément avec la classe CSS myClass:

process="@(.myClass :input)"

Voir:

Jaspe de Vries
la source
2
Notez que même JSF2.3 + prend en charge la plupart des mots-clés.
tandraschko