90

以下两段代码在listener放置方面有什么区别?

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

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

2 回答 2

187

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

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

当使用<f:ajax listener>代替时valueChangeListener,默认情况下它会在 HTML DOMchange事件期间执行。在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阶段期间被调用。那时,提交的值已经在模型中更新。您可以通过直接访问绑定到输入组件的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这种结构中的 a 被结合使用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
    // ...
}
于 2012-08-09T12:02:13.010 回答
9

对于第一个片段(ajax 侦听器属性):

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

但第二个片段(valueChangeListener):

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

*您可能想查看这个方便的答案

于 2012-08-09T08:20:14.903 回答