本文介绍了何时使用 valueChangeListener 或 f:ajax 侦听器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下两段代码之间的区别是什么 - 关于 listener 的位置?

What's the difference between the following two pieces of code - with regards to listener placement?

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

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

推荐答案

valueChangeListener 只会在表单提交时被调用并且提交的值与提交的值不同初始值.因此,当 only HTML DOM change 事件被触发时,它不会被调用.如果您想在 HTML DOM change 事件期间提交表单,那么您需要添加另一个 <f:ajax/> 而不使用侦听器(!) 到输入组件.它会导致表单提交只处理当前组件(如 execute="@this" 中所示).

The valueChangeListener will only be invoked when the form is submitted and the submitted value is different from the initial value. It's thus not invoked when only the HTML DOM change event is fired. If you would like to submit the form during the HTML DOM change event, then you'd need to add another <f:ajax/> without a listener(!) to the input component. It will cause a form submit which processes only the current component (as in execute="@this").

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

当使用 而不是 valueChangeListener 时,默认情况下它会在 HTML DOM change 事件期间执行.在 UICommand 组件和表示复选框或单选按钮的输入组件中,默认情况下它只会在 HTML DOM click 事件期间执行.


When using <f:ajax listener> instead of valueChangeListener, it would by default executed during the HTML DOM change event already. Inside UICommand components and input components representing a checkbox or radiobutton, it would be by default executed during the HTML DOM click event only.

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

另一个主要区别是 valueChangeListener 方法是在 PROCESS_VALIDATIONS 阶段结束时调用的.此时,提交的值尚未在模型中更新.因此,您不能仅通过访问绑定到输入组件的 value 的 bean 属性来获取它.您需要通过 ValueChangeEvent#getNewValue() 获取它.顺便说一下,旧值也可以通过 ValueChangeEvent#getOldValue() 获得.


Another major difference is that the valueChangeListener method is invoked during the end of the PROCESS_VALIDATIONS phase. At that moment, the submitted value is not been updated in the model yet. So you cannot get it by just accessing the bean property which is bound to the input component's value. You need to get it by ValueChangeEvent#getNewValue(). The old value is by the way also available by ValueChangeEvent#getOldValue().

public void changeListener(ValueChangeEvent event) {
    Object oldValue = event.getOldValue();
    Object newValue = event.getNewValue();
    // ...
}

方法在 INVOKE_APPLICATION 阶段被调用.此时,提交的值已在模型中更新.您可以通过直接访问绑定到输入组件的 value 的 bean 属性来获取它.


The <f:ajax listener> method is invoked during INVOKE_APPLICATION phase. At that moment, the submitted value is already been updated in the model. You can just get it by directly accessing the bean property which is bound to the input component's 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 来执行业务操作实际上一直是一种黑客/解决方法.


Also, if you would need to update another property based on the submitted value, then it would fail when you're using valueChangeListener as the updated property can be overridden by the submitted value during the subsequent UPDATE_MODEL_VALUES phase. That's exactly why you see in old JSF 1.x applications/tutorials/resources that a valueChangeListener is in such construct been used in combination with immediate="true" and FacesContext#renderResponse() to prevent that from happening. After all, using the valueChangeListener to execute business actions has actually always been a hack/workaround.

总结:仅当您需要拦截实际值更改本身时才使用 valueChangeListener.IE.您实际上对旧值和新值都感兴趣(例如记录它们).

Summarized: Use the valueChangeListener only if you need to intercept on the actual value change itself. I.e. you're actually interested in both the old and the new value (e.g. to log them).

public void changeListener(ValueChangeEvent event) {
    changeLogger.log(event.getOldValue(), event.getNewValue());
}

仅当您需要对新更改的值执行业务操作时才使用 .IE.您实际上对新值感兴趣(例如填充第二个下拉列表).

Use the <f:ajax listener> only if you need to execute a business action on the newly changed value. I.e. you're actually interested in only the new value (e.g. to populate a second dropdown).

public void ajaxListener(AjaxBehaviorEvent event) {
    selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}

如果您在执行业务操作时实际上也对旧值感兴趣,则回退到 valueChangeListener,但将其排入 INVOKE_APPLICATION 阶段.>

If you're actually also interested in the old value while executing a business action, then fall back to valueChangeListener, but queue it to the INVOKE_APPLICATION phase.

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
    // ...
}

这篇关于何时使用 valueChangeListener 或 f:ajax 侦听器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 10:41