以下两段代码之间的区别是什么listener
?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
和
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
Answers:
的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
// ...
}
logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );