何时使用valueChangeListener或f:ajax监听器?

时间:2012-08-09 08:05:17

标签: ajax jsf jsf-2 listener valuechangelistener

以下两段代码之间有什么区别 - 关于listener展示位置?

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

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

2 个答案:

答案 0 :(得分:175)

只有在提交表单提交的值与初始值不同时,才会调用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阶段结束时被调用。此时,尚未在模型中更新提交的值。所以你不能通过访问绑定到输入组件value的bean属性来获取它。您需要通过ValueChangeEvent#getNewValue()获取它。顺便提一下,ValueChangeEvent#getOldValue()也可以使用旧值。

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

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

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

答案 1 :(得分:9)

表示第一个片段(ajax listener属性):

ajax标记的“listener”属性是每次在客户端发生ajax函数时在服务器端调用的方法。例如,您可以使用此属性指定每次用户按下键时调用的服务器端函数

但第二个片段(valueChangeListener):

只有在提交表单时才会调用ValueChangeListener,而不是在输入值更改时调用

*您可能希望查看此handy answer