Коли використовувати valueChangeListener або f: ajax listener?


87

У чому різниця між наступними двома фрагментами коду - щодо listenerрозміщення?

<h:selectOneMenu ...>
    <f:selectItems ... />
    <f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>

і

<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
    <f:selectItems ... />
</h:selectOneMenu>

Відповіді:


182

valueChangeListenerБуде викликано тільки тоді , коли форма була відправлена і представлене значення відрізняється від початкового значення. Таким чином, він не викликається, коли запускається лишеchange подія HTML DOM . Якщо ви хочете надіслати форму під час changeподії HTML DOM , вам потрібно буде додати іншу <f:ajax/>без прослуховувача (!) До вхідного компонента. Це призведе до подання форми, яка обробляє лише поточний компонент (як у execute="@this").

<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
    <f:selectItems ... />
    <f:ajax />
</h:selectOneMenu>

При використанні <f:ajax listener>замість цього valueChangeListenerвін за замовчуванням виконується під час changeподії HTML DOM . Усередині UICommandкомпонентів та вхідних компонентів, що представляють прапорець або перемикач, воно за замовчуванням виконується лише під час clickподії HTML DOM .

<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, що a 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
    // ...
}

@BalusC, чи є причина не отримати старе значення від об'єкта підтримки в установці, перш ніж встановлювати його на нове значення, яке передається? Що - щось на зразок цього: logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );. Здається, ви могли б використовувати старі та нові значення, отримані таким чином, для ведення ділової логіки безпосередньо в сетері, а також для простого ведення журналу, але я не знаю, чи це може спричинити побічні ефекти ...
Лукас

Ідеальна і повна відповідь! Дякуємо, що поділилися своїми знаннями!
hbobenicio

@BalusC чи можна також отримати змінене значення через AjaxBehaviorEvent? У мене є <h: selectManyListbox, який прикутий до інших компонентів і хотів би використовувати змінене (Додане /
Видалене


Дякую @BalusC Але я не думаю, що ValueChangeListener впишеться в мій випадок, оскільки у мене є деякі значення виконання та візуалізації, як показано <f: ajax event = "valueChange" render = "tests" execute = "@ this" listener = "# {testController. processTimeTable} "/>
Paullo

9

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

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

але другий фрагмент (valueChangeListener):

ValueChangeListener буде викликаний лише тоді, коли буде подано форму, а не коли змінено значення вводу

* Ви можете переглянути цю зручну відповідь

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.