Когда использовать valueChangeListener или f:ajax listener?
В чем разница между следующими двумя частями кода - в отношении listener
размещение?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
а также
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
2 ответа
valueChangeListener
будет вызываться только тогда, когда форма отправлена и отправленное значение отличается от исходного значения. Таким образом, он не вызывается, когда только HTML DOM change
событие запущено. Если вы хотите отправить форму во время HTML DOM change
событие, то вам нужно будет добавить еще <f:ajax/>
без слушателя (!) для компонента ввода. Это приведет к отправке формы, которая обрабатывает только текущий компонент (как в execute="@this"
).
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
Когда используешь <f:ajax listener>
вместо valueChangeListener
по умолчанию выполняется во время HTML DOM change
событие уже внутри UICommand
компоненты и компоненты ввода, представляющие флажок или переключатель, по умолчанию он будет выполняться во время HTML DOM click
только событие
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Другое важное отличие состоит в том, что valueChangeListener
метод вызывается в конце PROCESS_VALIDATIONS
фаза. На данный момент представленное значение еще не обновлено в модели. Таким образом, вы не можете получить его, просто обращаясь к свойству bean-компонента, которое связано с компонентом ввода. value
, Вы должны получить это по ValueChangeEvent#getNewValue()
, Кстати, старое значение также доступно ValueChangeEvent#getOldValue()
,
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
<f:ajax listener>
метод вызывается во время INVOKE_APPLICATION
фаза. На данный момент представленное значение уже обновлено в модели. Вы можете просто получить его, непосредственно обращаясь к свойству bean-компонента, которое связано с компонентом ввода. value
,
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Кроме того, если вам потребуется обновить другое свойство в зависимости от переданного значения, оно не будет работать при использовании valueChangeListener
так как обновленное свойство может быть переопределено переданным значением во время последующего UPDATE_MODEL_VALUES
фаза. Именно поэтому вы видите в старых приложениях / руководствах / ресурсах JSF 1.x, что valueChangeListener
в такой конструкции был использован в сочетании с immediate="true"
а также FacesContext#renderResponse()
чтобы этого не случилось. В конце концов, используя valueChangeListener
Выполнение бизнес-действий всегда было хакерским решением.
Подведены итоги: используйте valueChangeListener
только если вам нужно перехватить фактическое изменение самого значения. Т.е. вы на самом деле интересуетесь как старым, так и новым значением (например, для их регистрации).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Использовать <f:ajax listener>
только если вам нужно выполнить бизнес-действие для вновь измененного значения. Т.е. вас на самом деле интересует только новое значение (например, для заполнения второго выпадающего списка).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
Если вы на самом деле также интересуетесь старой ценностью при выполнении бизнес-действия, тогда вернитесь к valueChangeListener
, но поставьте его в очередь INVOKE_APPLICATION
фаза.
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
// ...
}
Для первого фрагмента (атрибут слушателя ajax):
Атрибут "listener" тега ajax - это метод, который вызывается на стороне сервера каждый раз, когда функция ajax происходит на стороне клиента. Например, вы можете использовать этот атрибут, чтобы указать функцию на стороне сервера, которая будет вызываться каждый раз, когда пользователь нажимает клавишу
но второй фрагмент (valueChangeListener):
ValueChangeListener будет вызываться только при отправке формы, а не при изменении значения ввода
* вы можете посмотреть этот удобный ответ