ควรใช้ valueChangeListener หรือ f: ajax listener เมื่อใด


88

อะไรคือความแตกต่างระหว่างรหัสสองส่วนต่อไปนี้ - เกี่ยวกับlistenerตำแหน่ง?

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

และ

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

คำตอบ:


184

ระบบ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; // +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เฉพาะในกรณีที่คุณต้องการสกัดกั้นการเปลี่ยนแปลงค่าจริง กล่าวคือคุณสนใจทั้งค่าเก่าและค่าใหม่ (เช่นเพื่อบันทึก)

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
    // ...
}

@BalusC มีเหตุผลที่จะไม่รับค่าเก่าจากวัตถุสำรองใน setter ก่อนที่จะตั้งค่าเป็นค่าใหม่ที่ส่งผ่านหรือไม่? สิ่งนี้: logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );. ดูเหมือนว่าคุณสามารถใช้ค่าเก่าและใหม่ที่ได้รับในรูปแบบนั้นเพื่อทำตรรกะทางธุรกิจได้โดยตรงใน setter เช่นเดียวกับการบันทึกแบบง่ายๆ แต่ฉันไม่รู้ว่าสิ่งนี้จะทำให้เกิดผลข้างเคียงหรือไม่ ...
Lucas

ตอบโจทย์และสมบูรณ์แบบ! ขอบคุณที่แบ่งปันความรู้!
hbobenicio

@BalusC เป็นไปได้หรือไม่ที่จะรับค่าที่เปลี่ยนแปลงผ่าน AjaxBehaviorEvent ฉันมี <h: selectManyListbox ที่เชื่อมโยงกับส่วนประกอบอื่น ๆ และต้องการใช้การเปลี่ยนแปลง (เพิ่ม / ลบ) เพื่อดำเนินการบางอย่าง
Paullo


ขอบคุณ @BalusC แต่ฉันไม่คิดว่า ValueChangeListener จะเหมาะกับกรณีของฉันเพราะฉันมีค่า execute และ render ดังที่แสดง <f: ajax event = "valueChange" render = "testing" execute = "@ this" listener = "# {testController processTimeTable} "/>
Paullo

9

สำหรับส่วนแรก (แอตทริบิวต์ตัวฟัง ajax):

แอตทริบิวต์ "listener" ของแท็ก ajax คือเมธอดที่เรียกใช้ทางฝั่งเซิร์ฟเวอร์ทุกครั้งที่ฟังก์ชัน ajax เกิดขึ้นที่ฝั่งไคลเอ็นต์ ตัวอย่างเช่นคุณสามารถใช้แอตทริบิวต์นี้เพื่อระบุฟังก์ชันฝั่งเซิร์ฟเวอร์เพื่อเรียกทุกครั้งที่ผู้ใช้กดปุ่ม

แต่ส่วนที่สอง (valueChangeListener):

ValueChangeListener จะถูกเรียกเมื่อส่งแบบฟอร์มเท่านั้นไม่ใช่เมื่อค่าของอินพุตมีการเปลี่ยนแปลง

* คุณอาจต้องการดูคำตอบที่มีประโยชน์นี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.