何时使用 valueChangeListener 或 f:ajax 监听器?
Posted
技术标签:
【中文标题】何时使用 valueChangeListener 或 f:ajax 监听器?【英文标题】:When to use valueChangeListener or f:ajax listener? 【发布时间】: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>
【问题讨论】:
【参考方案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()
也可以使用旧值。
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
执行业务操作实际上一直是一种hack/workaround。
总结:仅当您需要拦截实际值更改本身时才使用valueChangeListener
。 IE。您实际上对 both 旧值和新值感兴趣(例如记录它们)。
public void changeListener(ValueChangeEvent event)
changeLogger.log(event.getOldValue(), event.getNewValue());
仅当您需要对新更改的值执行业务操作时才使用<f:ajax listener>
。 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 获取更改的值?我有 对于第一个片段(ajax 监听器属性):
ajax 标记的“listener”属性是每次在客户端发生 ajax 函数时在服务器端调用的方法。例如,您可以使用此属性来指定每次用户按下键时调用的服务器端函数
但是第二个片段(valueChangeListener):
ValueChangeListener 只会在表单提交时被调用,而不是在输入值改变时调用
*您可能想查看此handy answer
【讨论】:
以上是关于何时使用 valueChangeListener 或 f:ajax 监听器?的主要内容,如果未能解决你的问题,请参考以下文章
Valuechangelistener上 有效,但正在抛出异常。为什么?
JSF-将参数传递给 valuechangelistener
当初始值为空字符串且新值为 null 时调用 valueChangeListener
选择组件上的 Vaadin ValueChangeListener 无法正常工作
结合接缝 3 和 JSF2 复合组件 valueChangeListener 评估 El 表达式的问题
Primefaces valueChangeListener 或 <p:ajax 侦听器未触发 p:selectOneMenu [重复]