ระบบvalueChangeListenerจะเรียกใช้เมื่อมีการส่งแบบฟอร์มและค่าที่ส่งจะแตกต่างจากค่าเริ่มต้นเท่านั้น ดังนั้นจึงไม่ถูกเรียกใช้เมื่อมีการเริ่มต้นchangeเหตุการณ์HTML DOM เท่านั้น หากคุณต้องการส่งแบบฟอร์มระหว่างchangeเหตุการณ์HTML DOM คุณจะต้องเพิ่มแบบฟอร์มอื่น<f:ajax/>โดยไม่ต้องมี Listener (!) จะทำให้เกิดการส่งแบบฟอร์มซึ่งประมวลผลเฉพาะองค์ประกอบปัจจุบัน (ตามที่อยู่ในexecute="@this")
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
เมื่อใช้<f:ajax listener>แทนvalueChangeListenerโดยค่าเริ่มต้นจะดำเนินการในระหว่างchangeเหตุการณ์HTML DOM อยู่แล้ว UICommandส่วนประกอบภายในและส่วนประกอบอินพุตที่แสดงถึงช่องทำเครื่องหมายหรือปุ่มเรดิโอโดยค่าเริ่มต้นจะถูกเรียกใช้โดยค่าเริ่มต้นในระหว่างclickเหตุการณ์HTML DOM เท่านั้น
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
ความแตกต่างที่สำคัญอีกประการหนึ่งคือvalueChangeListenerวิธีการถูกเรียกใช้ในช่วงท้ายของPROCESS_VALIDATIONSเฟส ในขณะนั้นค่าที่ส่งยังไม่ได้รับการอัปเดตในแบบจำลอง valueดังนั้นคุณจึงไม่สามารถรับมันได้โดยเพียงแค่การเข้าถึงคุณสมบัติถั่วที่ถูกผูกไว้กับองค์ประกอบของการป้อนข้อมูล ValueChangeEvent#getNewValue()คุณต้องได้รับมันด้วย ValueChangeEvent#getOldValue()ค่าเดิมคือโดยวิธีการนี้ยังมีการ
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
}
<f:ajax listener>วิธีการถูกเรียกในระหว่างINVOKE_APPLICATIONขั้นตอนการ ในขณะนั้นค่าที่ส่งได้รับการอัปเดตแล้วในโมเดล valueคุณก็สามารถได้รับมันโดยการเข้าถึงโดยตรงคุณสมบัติถั่วที่ถูกผูกไว้กับองค์ประกอบของการป้อนข้อมูล
private Object value;
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value);
}
นอกจากนี้หากคุณต้องการอัปเดตคุณสมบัติอื่นตามมูลค่าที่ส่งมาก็จะล้มเหลวเมื่อคุณใช้valueChangeListenerเนื่องจากคุณสมบัติที่อัปเดตสามารถทำได้ถูกแทนที่ด้วยค่าที่ส่งในช่วงถัดUPDATE_MODEL_VALUESไป นั่นเป็นเหตุผลว่าทำไมคุณเห็นในเก่า JSF 1.x / โปรแกรมบทเรียน / ทรัพยากรที่valueChangeListenerอยู่ในโครงสร้างดังกล่าวถูกนำมาใช้ร่วมกับ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));
}
logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );. ดูเหมือนว่าคุณสามารถใช้ค่าเก่าและใหม่ที่ได้รับในรูปแบบนั้นเพื่อทำตรรกะทางธุรกิจได้โดยตรงใน setter เช่นเดียวกับการบันทึกแบบง่ายๆ แต่ฉันไม่รู้ว่าสิ่งนี้จะทำให้เกิดผลข้างเคียงหรือไม่ ...