Das valueChangeListenerwird nur aufgerufen, wenn das Formular gesendet wird und der übermittelte Wert vom Anfangswert abweicht. Es wird daher nicht aufgerufen, wenn nur das HTML-DOM- changeEreignis ausgelöst wird. Wenn Sie das Formular während des HTML-DOM- changeEreignisses 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 valueChangeListenerwird es standardmäßig bereits während des HTML-DOM- changeEreignisses ausgeführt. Innerhalb von UICommandKomponenten und Eingabekomponenten, die ein Kontrollkästchen oder einen Radiobutton darstellen, wird dieser standardmäßig nur während des HTML-DOM- clickEreignisses ausgeführt.
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Ein weiterer wesentlicher Unterschied besteht darin, dass die valueChangeListenerMethode am Ende der PROCESS_VALIDATIONSPhase 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_APPLICATIONPhase 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 valueChangeListeneraktualisieren 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 valueChangeListenerin 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 valueChangeListenerzur Ausführung von Geschäftsaktionen eigentlich immer ein Hack / Workaround.
Zusammengefasst: Verwenden valueChangeListenerSie 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_APPLICATIONPhase.
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 ...