Das valueChangeListener
wird nur aufgerufen, wenn das Formular gesendet wird und der übermittelte Wert vom Anfangswert abweicht. Es wird daher nicht aufgerufen, wenn nur das HTML-DOM- change
Ereignis ausgelöst wird. Wenn Sie das Formular während des HTML-DOM- change
Ereignisses senden möchten, müssen Sie <f:ajax/>
der Eingabekomponente ein weiteres Formular ohne Listener (!) Hinzufügen . Es wird ein Formular gesendet, das nur die aktuelle Komponente verarbeitet (wie in execute="@this"
).
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
Bei Verwendung von <f:ajax listener>
anstelle von valueChangeListener
wird es standardmäßig bereits während des HTML-DOM- change
Ereignisses ausgeführt. Innerhalb von UICommand
Komponenten und Eingabekomponenten, die ein Kontrollkästchen oder einen Radiobutton darstellen, wird dieser standardmäßig nur während des HTML-DOM- click
Ereignisses ausgeführt.
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Ein weiterer wesentlicher Unterschied besteht darin, dass die valueChangeListener
Methode am Ende der PROCESS_VALIDATIONS
Phase aufgerufen wird. Zu diesem Zeitpunkt wurde der übermittelte Wert im Modell noch nicht aktualisiert. Sie können es also nicht erhalten, indem Sie einfach auf die Bean-Eigenschaft zugreifen, die an die Eingabekomponente gebunden ist value
. Sie müssen es durch bekommen ValueChangeEvent#getNewValue()
. Der alte Wert ist übrigens auch bei verfügbar ValueChangeEvent#getOldValue()
.
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
Die <f:ajax listener>
Methode wird während der INVOKE_APPLICATION
Phase aufgerufen . Zu diesem Zeitpunkt wurde der übermittelte Wert bereits im Modell aktualisiert. Sie können es einfach erhalten, indem Sie direkt auf die Bean-Eigenschaft zugreifen, die an die Eingabekomponente gebunden ist value
.
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Wenn Sie eine andere Eigenschaft basierend auf dem übermittelten Wert valueChangeListener
aktualisieren müssten, schlägt dies bei der Verwendung fehl, da die aktualisierte Eigenschaft in der nachfolgenden Phase durch den übermittelten Wert überschrieben werden kannUPDATE_MODEL_VALUES
. Das ist genau , warum Sie in alten JSF 1.x - Anwendungen / tutorials / Ressourcen sehen , dass ein valueChangeListener
in einem solchen Konstrukt in Kombination verwendet worden mit immediate="true"
und FacesContext#renderResponse()
um zu verhindern , dass aus geschieht. Schließlich war die Verwendung von valueChangeListener
zur Ausführung von Geschäftsaktionen eigentlich immer ein Hack / Workaround.
Zusammengefasst: Verwenden valueChangeListener
Sie diese Option nur, wenn Sie die tatsächliche Wertänderung selbst abfangen müssen. Das heißt, Sie interessieren sich tatsächlich sowohl für den alten als auch für den neuen Wert (z. B. um sie zu protokollieren).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Verwenden <f:ajax listener>
Sie diese Option nur, wenn Sie eine Geschäftsaktion für den neu geänderten Wert ausführen müssen. Das heißt, Sie interessieren sich tatsächlich nur für den neuen Wert (z. B. um ein zweites Dropdown-Menü auszufüllen).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
Wenn Sie beim Ausführen einer Geschäftsaktion tatsächlich auch an dem alten Wert interessiert sind, greifen Sie auf zurück valueChangeListener
, stellen Sie ihn jedoch in die Warteschlange für die INVOKE_APPLICATION
Phase.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value)); // true
// ...
}
logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );
. Es scheint, als könnten Sie die alten und neuen Werte, die auf diese Weise erhalten wurden, verwenden, um Geschäftslogik direkt im Setter sowie einfache Protokollierung durchzuführen, aber ich weiß nicht, ob dies Nebenwirkungen verursachen würde ...