Когда использовать 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 будет вызываться только при отправке формы, а не при изменении значения ввода

* вы можете посмотреть этот удобный ответ

Другие вопросы по тегам