何时使用valueChangeListener或f:ajax监听器?
以下两段代码之间有什么区别 – 关于listener
位置?
<h:selectOneMenu ...> <f:selectItems ... /> <f:ajax listener="#{bean.listener}" /> </h:selectOneMenu>
和
<h:selectOneMenu ... valueChangeListener="#{bean.listener}"> <f:selectItems ... /> </h:selectOneMenu>
valueChangeListener
只会在表单提交时被调用, 并且提交的值与初始值不同。 因此, 只有 HTML DOM change
事件被触发时才会被调用。 如果您希望在HTML DOM change
事件期间提交表单,那么您需要添加另一个<f:ajax/>
而没有侦听器(!)到input组件。 它会导致一个表单提交哪个进程只处理当前的组件(如execute="@this"
)。
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}"> <f:selectItems ... /> <f:ajax /> </h:selectOneMenu>
当使用<f:ajax listener>
而不是valueChangeListener
,它将在HTML DOM change
事件过程中默认执行。 在表示checkbox或单选button的UICommand
组件和input组件内部,它将仅在HTML DOM click
事件期间默认执行。
<h:selectOneMenu value="#{bean.value}"> <f:selectItems ... /> <f:ajax listener="#{bean.ajaxListener}" /> </h:selectOneMenu>
另一个主要区别是在PROCESS_VALIDATIONS
阶段结束时调用valueChangeListener
方法。 此时,提交的值尚未在模型中更新。 所以你不能通过访问绑定到input组件value
的bean属性来获取它。 你需要通过ValueChangeEvent#getNewValue()
来获取它。 ValueChangeEvent#getOldValue()
方法也可以使用旧值。
public void changeListener(ValueChangeEvent event) { Object oldValue = event.getOldValue(); Object newValue = event.getNewValue(); // ... }
在INVOKE_APPLICATION
阶段调用<f:ajax listener>
方法。 此时,提交的值已经在模型中更新。 您可以通过直接访问绑定到input组件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
执行业务操作实际上一直是一个黑客/解决方法。
总结:仅当您需要截取实际值更改本身时才使用valueChangeListener
。 也就是说,你实际上对旧价值和新价值都感兴趣(例如logging它们)。
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 // ... }
对于第一个片段(ajax listener属性):
ajax标签的“listener”属性是每次在客户端发生ajax函数时在服务器端调用的方法。 例如,你可以使用这个属性来指定一个服务器端函数,每当用户按下一个键时调用
但第二个片段(valueChangeListener):
ValueChangeListener只会在表单提交时调用,而不是在input值改变时调用
*您可能想查看这个方便的答案