Когда использовать функцию 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>

Ответ 1

valueChangeListener будет вызываться только при отправке формы и переданное значение отличается от начального значения. Таким образом, он не вызывается, когда запускается только событие HTML DOM change. Если вы хотите отправить форму во время события HTML DOM change, вам нужно добавить еще один <f:ajax/> без прослушивателя (!) Во входной компонент. Это вызовет форму submit, которая обрабатывает только текущий компонент (как в 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
    // ...
}

Ответ 2

для первого фрагмента (атрибут прослушивателя ajax):

Атрибут "listenener" тега ajax - это метод, который вызывается на стороне сервера каждый раз, когда функция ajax происходит на стороне клиента. Например, вы можете использовать этот атрибут, чтобы указать функцию на стороне сервера для вызова каждый раз, когда пользователь нажал клавишу

но второй фрагмент (valueChangeListener):

ValueChangeListener вызывается только при отправке формы, а не при изменении значения ввода

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