Grundlegendes zu PrimeFaces-Prozess / Update und JSF f: ajax-Ausführungs- / Renderattributen

193

Was genau sind processund updatein PrimeFaces- p:commandXxxKomponenten und executeund renderin f:ajaxTags?

Was funktioniert zum Zeitpunkt der Validierung? Was macht updateAttribut, anstatt den Wert der Komponente vom Back-End zu aktualisieren? Bindet der processAttributwert an das Modell? Was genau tun @this, @parent, @allund @formin beiden Attributen?

Das folgende Beispiel funktioniert gut, aber ich bin ein wenig verwirrt in grundlegenden Konzepten.

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

Antworten:

306

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

Das processAttribut ist serverseitig und kann nur die UIComponentImplementierung EditableValueHolder(Eingabefelder) oder ActionSource(Befehlsfelder) beeinflussen. Das processAttribut teilt JSF mithilfe einer durch Leerzeichen getrennten Liste von Client-IDs mit, welche Komponenten beim (teilweisen) Senden des Formulars während des gesamten JSF-Lebenszyklus genau verarbeitet werden müssen.

JSF wird dann die Anfrage Werte gelten (HTTP - Request - Parameter auf die Komponente der eigenen Client - ID basiert zu finden und dann entweder als übermittelten Wert bei Einstellung EditableValueHolderKomponenten oder eine neue Schlange stehen ActionEventbei ActionSourceKomponenten), führen Konvertierung, Validierung und Aktualisierung der Modellwerte ( EditableValueHoldernur Komponenten) und schließlich die Warteschlange aufrufen ActionEvent( ActionSourcenur Komponenten). JSF überspringt die Verarbeitung aller anderen Komponenten, die nicht durch processAttribute abgedeckt sind . Außerdem werden Komponenten, deren renderedAttribut falsewährend der Phase der Anwendung von Anforderungswerten ausgewertet wird, als Teil des Schutzes vor manipulierten Anforderungen übersprungen.

Beachten Sie, dass es bei ActionSourceKomponenten (z. B. <p:commandButton>) sehr wichtig ist, dass Sie auch die Komponente selbst in das processAttribut aufnehmen, insbesondere wenn Sie die mit der Komponente verknüpfte Aktion aufrufen möchten. Das folgende Beispiel, das nur bestimmte Eingabekomponenten verarbeiten soll, wenn eine bestimmte Befehlskomponente aufgerufen wird, funktioniert also nicht:

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

Es würde nur das verarbeiten #{bean.foo}und nicht das #{bean.action}. Sie müssen auch die Befehlskomponente selbst einschließen:

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

Oder, wie Sie anscheinend herausgefunden haben, verwenden, @parentwenn sie zufällig die einzigen Komponenten sind, die ein gemeinsames übergeordnetes Element haben:

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

Wenn beide zufällig die einzigen Komponenten der übergeordneten UIFormKomponente sind, können Sie auch Folgendes verwenden @form:

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

Dies ist manchmal unerwünscht, wenn das Formular mehr Eingabekomponenten enthält, die Sie bei der Verarbeitung überspringen möchten, mehr als häufig, wenn Sie eine andere Eingabekomponente oder einen anderen UI-Abschnitt basierend auf der aktuellen Eingabekomponente in aktualisieren möchten eine Ajax-Listener-Methode. Sie möchten nämlich nicht, dass Validierungsfehler bei anderen Eingabekomponenten die Ausführung der Ajax-Listener-Methode verhindern.

Dann ist da noch die @all. Dies hat keine besonderen Auswirkungen auf das processAttribut, sondern nur auf das updateAttribut. A process="@all"verhält sich genauso wie process="@form". HTML unterstützt ohnehin nicht das gleichzeitige Senden mehrerer Formulare.

Es gibt übrigens auch eine, @nonedie nützlich sein kann, wenn Sie absolut nichts verarbeiten müssen, sondern nur einige bestimmte Teile über aktualisieren möchten update, insbesondere jene Abschnitte, deren Inhalt nicht von übermittelten Werten oder Aktionslistenern abhängt.

Es sollte beachtet werden, dass das processAttribut keinen Einfluss auf die Nutzlast der HTTP-Anforderung (die Anzahl der Anforderungsparameter) hat. Dies bedeutet, dass das Standard-HTML-Verhalten beim Senden von "alles", das in der HTML-Darstellung von enthalten <h:form>ist, nicht beeinflusst wird. Wenn Sie ein großes Formular haben und die Nutzlast der HTTP-Anforderung auf nur die für die Verarbeitung unbedingt erforderlichen reduzieren möchten, dh nur auf die von processAttributen abgedeckten , können Sie das partialSubmitAttribut in PrimeFaces Ajax-Komponenten wie in <p:commandXxx ... partialSubmit="true">oder festlegen <p:ajax ... partialSubmit="true">. Sie können dies auch "global" konfigurieren, indem Sie es bearbeiten web.xmlund hinzufügen

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

Alternativ können Sie auch <o:form>OmniFaces 3.0+ verwenden, das standardmäßig dieses Verhalten verwendet.

Das Standard-JSF, das den spezifischen PrimeFaces entspricht, processstammt executevon <f:ajax execute>. Es verhält sich genauso, außer dass es keine durch Kommas getrennte Zeichenfolge unterstützt, während die PrimeFaces-Zeichenfolge (obwohl ich persönlich empfehle, sich nur an die durch Leerzeichen getrennte Konvention zu halten) oder das @parentSchlüsselwort unterstützt. Es kann auch nützlich sein zu wissen, dass der <p:commandXxx process>Standardwert " @formwhile" <p:ajax process>und der <f:ajax execute>Standardwert " while" ist @this. Schließlich ist es auch nützlich zu wissen, dass processdie sogenannten "PrimeFaces-Selektoren" unterstützt werden, siehe auch Wie funktionieren PrimeFaces-Selektoren wie in update = "@ (. MyClass)"?


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

Das updateAttribut ist clientseitig und kann die HTML-Darstellung aller UIComponents beeinflussen. Das updateAttribut teilt JavaScript (das für die Verarbeitung der Ajax-Anforderung / Antwort verantwortlich ist) mithilfe einer durch Leerzeichen getrennten Liste von Client-IDs mit, welche Teile im HTML-DOM-Baum als Antwort auf die Formularübermittlung aktualisiert werden müssen.

JSF bereitet dann die richtige Ajax-Antwort dafür vor und enthält nur die angeforderten Teile, die aktualisiert werden sollen. JSF überspringt alle anderen Komponenten, die updatein der Ajax-Antwort nicht durch Attribute abgedeckt sind , wodurch die Nutzdaten der Antwort klein bleiben . Außerdem werden Komponenten übersprungen , deren renderedAttribut falsewährend der Renderantwortphase ausgewertet wird. Beachten Sie, dass trueJavaScript es im HTML-DOM-Baum nicht aktualisieren kann , obwohl es zurückkehren würde , wenn es ursprünglich war false. Sie müssten es stattdessen umbrechen oder das übergeordnete Element aktualisieren. Siehe auch Ajax Update / Render funktioniert nicht für eine Komponente, die ein Attribut gerendert hat .

Normalerweise möchten Sie nur die Komponenten aktualisieren , die auf der Clientseite beim (teilweisen) Senden des Formulars wirklich "aktualisiert" werden müssen. Im folgenden Beispiel wird das gesamte übergeordnete Formular aktualisiert über @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>

(Beachten Sie, dass das processAttribut weggelassen wird, da es standardmäßig @formbereits verwendet wird.)

Während dies gut funktionieren kann, ist die Aktualisierung der Eingabe- und Befehlskomponenten in diesem speziellen Beispiel nicht erforderlich. Wenn Sie die Modellwerte foound die barInside- actionMethode nicht ändern (was in der UX-Perspektive wiederum nicht intuitiv wäre), ist es sinnlos, sie zu aktualisieren. Die Nachrichtenkomponenten sind die einzigen, die wirklich aktualisiert werden müssen:

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

Das wird jedoch langweilig, wenn Sie viele davon haben. Dies ist einer der Gründe, warum PrimeFaces Selectors existieren. Diese Nachrichtenkomponenten haben in der generierten HTML-Ausgabe eine gemeinsame Stilklasse von ui-message, daher sollte auch Folgendes gelten:

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

(Beachten Sie, dass Sie die IDs für Nachrichtenkomponenten behalten sollten, da dies sonst @(...)nicht funktioniert . Weitere Informationen finden Sie unter Funktionsweise von PrimeFaces-Selektoren wie in update = "@ (. myClass)". )

Das @parentaktualisiert nur die übergeordnete Komponente, die somit die aktuelle Komponente und alle Geschwister und ihre untergeordneten Komponenten abdeckt. Dies ist nützlicher, wenn Sie das Formular in vernünftigen Gruppen mit jeweils eigener Verantwortung getrennt haben. Die @thisUpdates sind natürlich nur die aktuelle Komponente. Normalerweise ist dies nur erforderlich, wenn Sie eines der HTML-Attribute der Komponente in der Aktionsmethode ändern müssen. Z.B

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

Stellen Sie sich vor, dass die oncompleteNotwendigkeit besteht, mit dem zu arbeiten, valuewas geändert actionwurde. Dann hätte dieses Konstrukt nicht funktioniert, wenn die Komponente nicht aktualisiert worden wäre, aus dem einfachen Grund, der oncompleteTeil der generierten HTML-Ausgabe ist (und daher werden alle darin enthaltenen EL-Ausdrücke ausgewertet während der Renderantwort).

Das @allaktualisiert das gesamte Dokument, das mit Vorsicht verwendet werden sollte. Normalerweise möchten Sie dafür eine echte GET-Anforderung verwenden, entweder über einen einfachen Link ( <a>oder <h:link>) oder eine Umleitung nach dem POST durch ?faces-redirect=trueoder ExternalContext#redirect(). Hat in Effekten process="@form" update="@all"genau den gleichen Effekt wie ein Nicht-Ajax-Submit (nicht partiell). In meiner gesamten JSF-Karriere bestand der einzige sinnvolle Anwendungsfall @alldarin, eine Fehlerseite vollständig anzuzeigen, falls während einer Ajax-Anforderung eine Ausnahme auftritt. Siehe auch Wie gehe ich mit JSF 2.0-Ausnahmen für AJAXified-Komponenten richtig um?

Das Standard-JSF, das den spezifischen PrimeFaces entspricht, updatestammt rendervon <f:ajax render>. Es verhält sich genauso, außer dass es keine durch Kommas getrennte Zeichenfolge unterstützt, während die PrimeFaces-Zeichenfolge (obwohl ich persönlich empfehle, sich nur an die durch Leerzeichen getrennte Konvention zu halten) oder das @parentSchlüsselwort unterstützt. Beides updateund renderstandardmäßig @none(was "nichts" ist).


Siehe auch:

BalusC
quelle
Wenn ich update = "" verwende, wird die verwaltete Eigenschaft der Backing Bean nicht festgelegt und meine @ PostConstruct-Routine schlägt fehl. Irgendwelche Gedanken? BEARBEITEN: • Wenn Sie sich darauf verlassen, dass eine verwaltete Eigenschaft von # {param} in den nachfolgenden POST-Anforderungen vorhanden ist, müssen Sie sie als <f: param> in die UICommand-Komponenten aufnehmen.
K.Nicholas
Möglicherweise verarbeitet / aktualisiert ein Prozess / eine Aktualisierung einer panelGroup den Inhalt dieser panelGroup. Beispiel: <h: panelGroup id = "pgId"> // Eingabetexte finden Sie hier. <h: panelGroup> <p: commandLink process = "pgId" -Update = "pgId" />
Bob-Cac
Danke @BalusC für diese sehr schöne Erklärung!
ProgrammingIsAwsome
2
@Rapster: Da processnicht festgelegt ist, wird der Standardwert von verwendet @form. Dies wird auch in der obigen Antwort erklärt.
BalusC
2
@ Roland: Es verbirgt ein anderes, schwerwiegenderes Problem mit der App-Konfiguration.
BalusC
54

Wenn Sie Schwierigkeiten haben, sich an die Standardwerte zu erinnern (ich weiß, ich habe ...), finden Sie hier einen kurzen Auszug aus der Antwort von BalusC:

Komponente | Senden | Aktualisierung
------------ | --------------- | --------------
f: ajax | execute = "@ this" | render = "@ none"
p: ajax | process = "@ this" | update = "@ none"
p: commandXXX | process = "@ form" | update = "@ none"
Jaqen H'ghar
quelle
Nur eine kleine Korrektur: Der Standardwert von processfür p:commandXXXist @all. Außerdem scheint dies für jede Komponente zu gelten, die AJAX unterstützt, wie z p:menuitem.
Stephan Rauh
1
Hallo @StephanRauh, vielen Dank für den Kommentar. Wo haben Sie die Standardeinstellung gelesen @all? Soweit ich aus der Antwort von BalusC lesen kann, ist dies @formjedoch @allgleichbedeutend mit @formin Bearbeitung. Guter Punkt zu den anderen Komponenten, ich denke, ich muss im Quellcode nachsehen, wann es Zeit ist, um zu sehen, für welche Komponenten es gilt, da ich lieber nichts schreiben möchte, was möglicherweise falsch ist
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko hat mir von dem @allStück erzählt . Er muss wissen, dass er kürzlich die AJAX-Engine von PrimeFaces neu implementiert hat. Später habe ich es noch einmal überprüft, aber den Quellcode von PrimeFaces gelesen und mir die XHR-Anforderungen angesehen. Ich hoffe, ich habe es diesmal richtig gemacht, da ich die AJAX-Anforderungen von BootsFaces so implementiert habe, dass sie identisch mit den AJAX-Anforderungen von PrimeFaces funktionieren.
Stephan Rauh
Es wäre irreführend zu sagen, dass der Standardwert @all ist, wenn HTML das Senden mehrerer Formulare nicht unterstützt. Entwickler müssen den effektiven Standardwert kennen (damit Thomas ihn möglicherweise entsprechend ändert). Übrigens sind diese Standardeinstellungen im Primefaces-Benutzerhandbuch 6.2 fälschlicherweise als null definiert.
Marc Dzaebel
27

Durch den Prozess (in der JSF-Spezifikation heißt es "Ausführen") weisen Sie JSF an, die Verarbeitung auf Komponenten zu beschränken, die angegeben werden. Alles andere wird einfach ignoriert.

update gibt an, welches Element aktualisiert wird, wenn der Server auf Ihre Anfrage antwortet.

@all : Jede Komponente wird verarbeitet / gerendert.

@this : Die anfordernde Komponente mit dem Execute-Attribut wird verarbeitet / gerendert.

@form : Das Formular, das die anfordernde Komponente enthält, wird verarbeitet / gerendert.

@parent : Das übergeordnete Element , das die anfordernde Komponente enthält, wird verarbeitet / gerendert.

Mit Primefaces können Sie sogar JQuery-Selektoren verwenden. Schauen Sie sich diesen Blog an: http://blog.primefaces.org/?p=1867

faissalb
quelle
2

Bitte beachten Sie, dass PrimeFaces die Standardschlüsselwörter JSF 2.0+ unterstützt:

  • @this Aktuelle Komponente.
  • @all Ganze Ansicht.
  • @form Nächste Ahnenform der aktuellen Komponente.
  • @none Keine Komponente.

und die Standard-Schlüsselwörter JSF 2.3+:

  • @child(n) n-tes Kind.
  • @composite Nächster Vorfahr der zusammengesetzten Komponente.
  • @id(id) Wird verwendet, um Komponenten anhand ihrer ID zu durchsuchen, wobei die Komponentenbaumstruktur ignoriert und Container benannt werden.
  • @namingcontainer Der nächstgelegene Ahnenbenennungscontainer der aktuellen Komponente.
  • @parent Übergeordnetes Element der aktuellen Komponente.
  • @previous Vorheriges Geschwister.
  • @next Nächstes Geschwister.
  • @root Die UIViewRoot-Instanz der Ansicht kann verwendet werden, um die Suche im Stammverzeichnis anstelle der aktuellen Komponente zu starten.

Es enthält jedoch auch einige PrimeFaces-spezifische Schlüsselwörter:

  • @row(n) n-te Reihe.
  • @widgetVar(name) Komponente mit angegebenem widgetVar.

Sie können sogar "PrimeFaces Selectors" verwenden, mit denen Sie die jQuery Selector-API verwenden können. So verarbeiten Sie beispielsweise alle Eingaben in einem Element mit der CSS-Klasse myClass:

process="@(.myClass :input)"

Sehen:

Jasper de Vries
quelle
2
Beachten Sie, dass sogar JSF2.3 + die meisten Schlüsselwörter unterstützt.
Tandraschko