【问题标题】:When to use valueChangeListener or f:ajax listener?何时使用 valueChangeListener 或 f:ajax 监听器?
【发布时间】:2012-08-06 10:13:32
【问题描述】:

关于listener 放置,以下两段代码有什么区别?

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

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

【问题讨论】:

    标签: ajax jsf jsf-2 listener valuechangelistener


    【解决方案1】:

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

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

    当使用 &lt;f:ajax listener&gt; 而不是 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();
        // ...
    }
    

    &lt;f:ajax listener&gt; 方法在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 应用程序/教程/资源中看到 valueChangeListenerimmediate="true"FacesContext#renderResponse() 结合使用以防止这种情况发生的原因。毕竟,使用valueChangeListener 执行业务操作实际上一直是一种hack/workaround。

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

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

    仅当您需要对新更改的值执行业务操作时才使用&lt;f:ajax listener&gt;。 IE。您实际上只对新值感兴趣(例如,填充第二个下拉菜单)。

    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,是否有理由不从设置器中的支持对象获取 old 值,然后再将其设置为 new 值是通过了吗?像这样的东西:logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );。似乎您可以使用以这种方式获得的旧值和新值直接在 setter 中执行 业务逻辑 以及简单的日志记录,但我不知道这是否会导致副作用.. .
    • @BalusC 是否也可以通过 AjaxBehaviorEvent 获取更改的值?我有
    • 谢谢@BalusC 但我认为 ValueChangeListener 不适合我的情况,因为我有一些执行和渲染值,如图所示
    • 我确实发现这个答案对我今天发布的问题很有帮助stackoverflow.com/questions/34926653/…,我更改了 System.out.println("dateValueChanged : "+ date.toString()); with System.out.println("dateValueChanged : "+ event.getNewValue());
    【解决方案2】:

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

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

    但是第二个片段(valueChangeListener):

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

    *您可能想查看此handy answer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-02
      • 2017-02-12
      • 2012-07-06
      • 2011-06-21
      • 2012-08-26
      • 1970-01-01
      • 2013-07-27
      • 2012-01-25
      相关资源
      最近更新 更多