เหตุใดเหตุการณ์การเปลี่ยนแปลง jquery จึงไม่ทริกเกอร์เมื่อฉันตั้งค่าตัวเลือกโดยใช้ val ()


377

ตรรกะในchange()ตัวจัดการเหตุการณ์ไม่ได้ถูกเรียกใช้เมื่อตั้งค่าตามval()แต่มันจะทำงานเมื่อผู้ใช้เลือกค่าด้วยเมาส์ ทำไมนี้

<select id="single">
    <option>Single</option>
    <option>Single2</option>
</select>

<script>
    $(function() {
        $(":input#single").change(function() {
           /* Logic here does not execute when val() is used */
        });
    });

    $("#single").val("Single2");
</script>

คำตอบ:


589

เพราะchangeเหตุการณ์ต้องการเหตุการณ์เบราว์เซอร์จริงที่เริ่มต้นโดยผู้ใช้แทนผ่านรหัสจาวาสคริปต์

ทำสิ่งนี้แทน:

$("#single").val("Single2").trigger('change');

หรือ

$("#single").val("Single2").change();

1
สวัสดีทำแบบเลื่อนลงอัปเดตนี้ แต่การเรียก onChange () ซ้ำ ๆ
Pankaj

3
ฉันขุดคำตอบนี้ มันใช้งานได้ แต่ไม่มีวิธีที่ดีกว่าใน jQuery ใช่ไหม ฉันแน่ใจว่าเราทุกคนจะจำที่จะทำเช่นนี้ทุกครั้งที่เราเปลี่ยนค่าที่มีการตั้งค่าตัวจัดการการเปลี่ยนแปลง (การเสียดสี) กรอบการทำงานที่ใช้การผูกข้อมูลอาจแก้ปัญหานี้ได้ดีกว่า
เจส

@ user113716 คุณจะรู้วิธีการทิกเกอร์โดยไม่ทราบค่าใด ๆ หรือไม่?
BKSpurgeon

4
ฉันยอมรับว่านี่เป็นคำตอบที่ถูกต้อง แต่สิ่งนี้แย่มากและทำลายสิ่งที่ฉันพยายามทำ
ดัสติน Poissant

ลองใช้ $ ("# single") trigger ({type: "change", val: "Single2"})
user2901633

44

ฉันเชื่อว่าคุณสามารถเรียกใช้เหตุการณ์การเปลี่ยนแปลงด้วยตนเองtrigger():

$("#single").val("Single2").trigger('change');

แม้ว่าทำไมมันไม่ทำงานโดยอัตโนมัติ แต่ฉันก็ยังไม่รู้


ฉันไม่สามารถทำงานนี้ได้เช่นกัน $ ("# single"). val ("Single2"). change (); ฉันกำลังสร้างดร็อปดาวน์แบบไดนามิกและเปลี่ยนค่าของมัน (มันใช้ได้ดีสำหรับฉัน) แต่เมื่อฉันพยายามที่จะทริกเกอร์การเปลี่ยนแปลงมันจะไม่ทำงานสำหรับฉัน
Maneesh Kumar

4
"บิต" ล่าช้า แต่มันไม่ทำงานโดยอัตโนมัติเพราะจะทำให้เกิดการวนซ้ำไม่สิ้นสุด คิดว่า$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ

@Juhana ฉันคิดว่าการวนซ้ำไม่สิ้นสุดนั้นง่ายต่อการสังเกตวินิจฉัยและแก้ไขมากกว่า val () ไม่สามารถเรียกการเปลี่ยนแปลง "ผูก" อย่างลึกลับได้
iono

การโทร. change () เป็นการจดชวเลขสำหรับการโทร. trigger ('change')
Triynko

9

การเพิ่มโค้ดนี้หลังจาก val () ดูเหมือนว่าจะทำงาน:

$(":input#single").trigger('change');

6
ใช่ แต่คุณไม่จำเป็นต้องทำเลือก DOM $(":input#single")ที่แยกต่างหากสำหรับมันด้วย ในความเป็นจริงคุณไม่ควร .val()เพียงแค่โซ่หลังจากที่ คุณสามารถใช้หรือ.trigger('change') .change()มันเหมือนกันหมด
user113716

8

เท่าที่ฉันสามารถอ่านได้ใน API เหตุการณ์จะเริ่มทำงานก็ต่อเมื่อผู้ใช้คลิกที่ตัวเลือก

http://api.jquery.com/change/

สำหรับกล่องที่เลือกช่องทำเครื่องหมายและปุ่มตัวเลือกเหตุการณ์จะถูกยิงทันทีเมื่อผู้ใช้ทำการเลือกด้วยเมาส์ แต่สำหรับองค์ประกอบอื่น ๆ ประเภทเหตุการณ์จะถูกเลื่อนออกไปจนกว่าองค์ประกอบจะหมดโฟกัส


ทางเลือกสำหรับองค์ประกอบองค์ประกอบอื่น ๆ คืออะไร? ฉันต้องการให้เหตุการณ์ 'เปลี่ยน' เริ่มต้นทันทีสำหรับinputองค์ประกอบไม่ใช่เมื่อองค์ประกอบเสียโฟกัส คุณรู้หรือไม่
Dan Nissenbaum

1
หากโดย "ทันที" คุณหมายถึง "เมื่อใดก็ตามที่มีการกดปุ่มในอินพุต" คุณกำลังมองหากิจกรรม onkeyup, onkeypress และ onkeydown ไม่ใช่การเปลี่ยน
2867288

6

เพื่อให้ง่ายต่อการเพิ่มฟังก์ชั่นที่กำหนดเองและเรียกมันเมื่อคุณต้องการเปลี่ยนค่าที่เรียกการเปลี่ยนแปลง

$.fn.valAndTrigger = function (element) {
    return $(this).val(element).trigger('change');
}

และ

$("#sample").valAndTirgger("NewValue");

หรือคุณสามารถแทนที่ฟังก์ชัน val เพื่อเรียกการเปลี่ยนแปลงเมื่อเรียกว่า val เสมอ

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        this.trigger("change");
        return originalVal.call(this, value);
    };
})(jQuery);

ตัวอย่างที่http://jsfiddle.net/r60bfkub/


เบราว์เซอร์ของฉันบ่นว่ามีการวนซ้ำมากเกินไปการแก้ไขใด ๆ
Bhargav Nanekalva

คุณกำลังฟัง - changeเหตุการณ์ผ่านการควบคุมและดำเนินการติดต่อกลับที่ (โดยตรงหรือโดยอ้อม) เรียกอีกครั้ง - changeกิจกรรมมากกว่าการควบคุมเดียวกัน ฉันขอแนะนำให้คุณใช้ชื่ออื่นสำหรับเหตุการณ์ที่คุณเปิดใช้งานด้วยตนเอง (เช่นexplicit.change) เพื่อที่จะไม่เรียกเหตุการณ์change-event ป้องกันลูปและยังช่วยให้คุณตอบสนองต่อเหตุการณ์
Kamafeather

3

ในกรณีที่คุณไม่ต้องการรวมกับเหตุการณ์การเปลี่ยนแปลงเริ่มต้นคุณสามารถจัดกิจกรรมที่กำหนดเองของคุณ

$('input.test').on('value_changed', function(e){
    console.log('value changed to '+$(this).val());
});

เพื่อทริกเกอร์เหตุการณ์ในชุดค่าคุณสามารถทำได้

$('input.test').val('I am a new value').trigger('value_changed');

3

ฉันพบปัญหาเดียวกันในขณะที่ใช้ CMB2 กับ Wordpress และต้องการเชื่อมโยงกับเหตุการณ์การเปลี่ยนแปลงของไฟล์อัปโหลดไฟล์ metabox

ดังนั้นในกรณีที่คุณไม่สามารถแก้ไขโค้ดที่เรียกใช้การเปลี่ยนแปลง (ในกรณีนี้คือสคริปต์ CMB2) ให้ใช้รหัสด้านล่าง ทริกเกอร์กำลังถูกเรียกใช้หลังจากมีการตั้งค่ามิฉะนั้นเหตุการณ์การเปลี่ยนแปลงของคุณ Handler จะทำงาน แต่ค่าจะเป็นค่าก่อนหน้าไม่ใช่ค่าที่ตั้งไว้

นี่คือรหัสที่ฉันใช้:

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        if (arguments.length >= 1) {
            // setter invoked, do processing
            return originalVal.call(this, value).trigger('change');
        }
        //getter invoked do processing
        return originalVal.call(this);
    };
})(jQuery);

นี่เป็นสิ่งที่ดี แต่คุณสามารถแสดงได้อย่างไรว่าคุณจะ จำกัด ให้มีเพียงหนึ่งอินพุตเท่านั้นหรือไม่
jwebb

@jwebb ไม่แน่ใจว่าคุณหมายถึงอะไร? เรากำลังเอาชนะฟังก์ชัน jQuery val () คุณผูกตัวจัดการเหตุการณ์การเปลี่ยนแปลงกับอินพุตที่ระบุ
user2075039

ฉันหมายถึง @ user2075039 จะเกิดอะไรขึ้นถ้ามีหลายอินพุตในหน้าโดยใช้ฟังก์ชัน jQuery val () และคุณไม่ต้องการผูกตัวจัดการเหตุการณ์การเปลี่ยนแปลงที่กำหนดเองกับพวกเขาทั้งหมดเพียงแค่หนึ่งในนั้น?
jwebb

@ jwebb คุณสามารถตรวจสอบthis.selectorภายใน$.fn.valฟังก์ชั่นเอาชนะสำหรับตัวเลือกเฉพาะ (จะขึ้นอยู่กับสิ่งที่ใช้สำหรับตัวเลือก) นี่เป็นสิ่งที่ดีที่สุดที่ฉันพบในการทำสิ่งนี้เฉพาะกับเขตข้อมูลเฉพาะปัญหาเดียวคือคุณต้องรู้ว่าสิ่งที่พวกเขาใช้สำหรับตัวเลือก
sMyles

1
$(":input#single").trigger('change');

สิ่งนี้ใช้ได้กับสคริปต์ของฉัน ฉันมีคอมโบ 3 รายการ & ผูกกับเหตุการณ์ chainSelect ฉันต้องผ่าน 3 ค่าโดย url & ค่าเริ่มต้นเลือกดร็อปดาวน์ทั้งหมด ฉันใช้สิ่งนี้

$('#machineMake').val('<?php echo $_GET['headMake']; ?>').trigger('change');

และเหตุการณ์แรกทำงาน


10
ฉันหวังว่าคุณจะไม่ทำสิ่งนี้ในโลกแห่งความเป็นจริง ไม่จำเป็นต้องบอกว่า $ _GET ['อะไรก็ตาม'] ไม่สามารถเชื่อถือได้
เดนิส V

1

หากคุณเพิ่งเพิ่มตัวเลือกที่เลือกไปยังแบบฟอร์มและคุณต้องการที่จะทริกเกอร์เหตุการณ์การเปลี่ยนแปลงฉันได้พบว่าจำเป็นต้องมี setTimeout มิฉะนั้น jQuery จะไม่รับกล่องตัวเลือกที่เพิ่มเข้ามาใหม่:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.