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


87

以下两段代码之间的区别是什么listener

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

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

Answers:


182

valueChangeListener形式被提交时将只被调用提交的值是从初始值不同。因此,change触发HTML DOM事件时不会调用它。如果要在HTML DOMchange事件期间提交表单,则需要<f:ajax/>在输入组件中添加另一个没有listener(!)的表单。它将导致仅处理当前组件的表单提交(如中所述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阶段中被调用。那时,提交的值已在模型中更新。您可以通过直接访问绑定到输入组件的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这样的结构中的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
    // ...
}

@BalusC,是否有理由在将其设置为传入的值之前不从设置器中的后备对象获取值?这样的东西:。似乎您可以使用以这种方式获得的旧值和新值直接在设置器中进行业务逻辑以及简单的日志记录,但是我不知道这是否会带来副作用……logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );
Lucas 2013年

完美而完整的答案!感谢您分享您的知识!
hbobenicio

@BalusC是否也可以通过AjaxBehaviorEvent获取更改的值?我有<h:selectManyListbox,它已链接到其他组件,并且希望使用更改后的(已添加/已删除)来执行某些操作
Paullo


谢谢@BalusC但是我不认为ValueChangeListener会适合我的情况,因为我有一些执行和呈现值,如图所示:<f:ajax event =“ valueChange” render =“ tests” execute =“ @ this” listener =“#{testController。 processTimeTable}“ />
Paullo

9

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

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

但是第二个片段(valueChangeListener):

仅当提交表单时才调用ValueChangeListener,而不是在更改输入值时调用

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.