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

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




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


#1 楼

仅当提交表单并且提交的值与初始值不同时,才调用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()也可以使用旧值。那时,提交的值已在模型中更新。您可以直接访问绑定到输入组件<f:ajax listener>的bean属性来获取它。

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



另外,如果您需要基于提交的值来更新另一个属性,那么当您使用INVOKE_APPLICATION时,它将失败,因为在后续的value阶段,更新的属性可以被提交的值覆盖。这就是为什么您在旧的JSF 1.x应用程序/教程/资源中看到valueChangeListenerUPDATE_MODEL_VALUESvalueChangeListener结合使用以防止这种情况的发生的原因。毕竟,使用immediate="true"来执行业务操作实际上一直是一个hack /解决方法。总结:仅当您需要拦截实际值更改本身时,才使用FacesContext#renderResponse()。即您实际上对旧值和新值都感兴趣(例如记录它们)。

private Object value; // +getter+setter.

public void ajaxListener(AjaxBehaviorEvent event) {
    System.out.println(value); // Look, (new) value is already set.
}


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

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


如果您实际上在执行a时也对旧值感兴趣商业行动,然后退回到valueChangeListener,但将其排入<f:ajax listener>阶段。

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


评论


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

–卢卡斯
2013年1月4日23:06

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

– hbobenicio
2015年1月12日14:48在

@BalusC是否也可以通过AjaxBehaviorEvent获取更改的值?我有
– Paullo
15年7月7日在20:22

@Paullo:stackoverflow.com/questions/14750185 / ...

– BalusC
15年7月7日在20:29

谢谢@BalusC但是我不认为ValueChangeListener会适合我的情况,因为我有一些执行和呈现值,如图所示:

– Paullo
2015年7月7日在20:58



#2 楼

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

ajax标记的“ listener”属性是一种方法,每次客户端发生ajax函数时,就会在服务器端调用此方法。例如,您可以使用此属性指定每次用户按下键时调用的服务器端函数,但第二个片段(valueChangeListener):

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

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