Mengapa jquery mengubah acara tidak memicu ketika saya menetapkan nilai pilih menggunakan val ()?


377

Logika dalam change()event handler tidak dijalankan ketika nilai ditetapkan oleh val(), tetapi dijalankan ketika pengguna memilih nilai dengan mouse mereka. Kenapa ini?

<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>

Jawaban:


589

Karena changeacara tersebut membutuhkan acara browser aktual yang diprakarsai oleh pengguna alih-alih melalui kode javascript.

Lakukan ini sebagai gantinya:

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

atau

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

1
Hai, lakukan pembaruan ini di bawah. tetapi dipanggil onChange () secara rekursif.
Pankaj

3
Saya menggali jawaban ini. Ini bekerja, tetapi tidak adakah cara yang lebih baik dengan jQuery? Saya yakin kita semua akan ingat untuk melakukan ini setiap kali kita mengubah nilai yang memiliki pengaturan handler diatur (sarkasme). Kerangka kerja yang menggunakan pengikatan data mungkin bisa menyelesaikan ini dengan lebih baik?
Jess

@ user113716, bisakah Anda tahu cara mengoyaknya tanpa mengetahui nilai apa pun?
BKSpurgeon

4
Saya setuju ini adalah jawaban yang benar tetapi ini benar-benar menyebalkan dan merusak apa yang saya coba lakukan.
Dustin Poissant

Coba $ ("# tunggal"). Trigger ({type: "change", val: "Single2"})
user2901633

44

Saya yakin Anda dapat memicu acara perubahan secara manual dengan trigger():

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

Meskipun mengapa itu tidak menyala secara otomatis, saya tidak tahu.


Saya tidak bisa mengerjakan ini, juga $ ("# single"). Val ("Single2"). Change (); Saya secara dinamis membuat dropdown dan mengubah nilainya (Ini berfungsi dengan baik untuk saya) Tetapi ketika saya mencoba untuk memicu perubahan itu tidak berfungsi untuk saya.
Maneesh Kumar

4
"Sedikit" terlambat tetapi tidak aktif secara otomatis karena akan menyebabkan loop tak terbatas. Pikirkan$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ

@ Juhana Saya pikir infinite loop jauh lebih mudah untuk diperhatikan, didiagnosis, dan diperbaiki daripada val () yang secara misterius gagal memicu ikatan "perubahan".
iono

Memanggil .change () adalah singkatan untuk memanggil .trigger ('change').
Triynko

9

Menambahkan potongan kode ini setelah val () tampaknya berfungsi:

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

6
Ya, tetapi Anda tidak perlu melakukan pemilihan DOM terpisah untuk itu $(":input#single"). Sebenarnya Anda tidak seharusnya melakukannya. Hanya rantai setelah .val(). Anda bisa menggunakan .trigger('change')atau .change(). Mereka sama persis.
user113716

8

Sejauh yang saya bisa baca di API. Acara ini hanya dipecat ketika pengguna mengklik opsi.

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

Untuk kotak pilih, kotak centang, dan tombol radio, acara tersebut dipecat segera ketika pengguna membuat pilihan dengan mouse, tetapi untuk jenis elemen lainnya acara ditangguhkan hingga elemen kehilangan fokus.


Apa alternatif untuk jenis elemen lainnya? Saya ingin acara 'perubahan' segera diaktifkan untuk inputelemen, bukan ketika elemen kehilangan fokus. Apakah anda tahu
Dan Nissenbaum

1
Jika dengan "segera" maksud Anda "setiap kali tombol ditekan pada input" Anda sedang mencari onkeyup, onkeypress, dan peristiwa onkeydown, bukan onchange.
user2867288

6

Untuk membuatnya lebih mudah, tambahkan fungsi kustom dan panggil kapan saja Anda inginkan bahwa mengubah nilai juga memicu perubahan

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

dan

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

Atau Anda dapat mengganti fungsi val untuk selalu memanggil perubahan saat val dipanggil

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

Contoh di http://jsfiddle.net/r60bfkub/


Browser saya mengeluh terlalu banyak rekursi, ada perbaikan untuk ini?
Bhargav Nanekalva

Anda sedang mendengarkan untuk change-event atas kontrol dan menjalankan callback yang (langsung atau tidak langsung) memicu lagi change-event atas kontrol yang sama. Saya menyarankan Anda untuk menggunakan nama lain untuk acara yang Anda memicu secara manual (misalnya explicit.change), sehingga tidak memicu kembali change-Event, mencegah loop, dan masih memungkinkan Anda untuk bereaksi terhadap acara tersebut.
Kamafeather

3

Jika Anda tidak ingin bergabung dengan acara perubahan standar, Anda dapat menyediakan acara khusus Anda

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

untuk memicu acara pada nilai yang ditetapkan, Anda bisa melakukannya

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

3

Saya mengalami masalah yang sama saat menggunakan CMB2 dengan Wordpress dan ingin menghubungkan ke acara perubahan dari file upload metabox.

Jadi jika Anda tidak dapat mengubah kode yang meminta perubahan (dalam hal ini skrip CMB2), gunakan kode di bawah ini. Pemicu sedang dipanggil SETELAH nilai ditetapkan, jika tidak, eventHandler perubahan Anda akan berfungsi, tetapi nilainya akan menjadi yang sebelumnya, bukan yang ditetapkan.

Berikut kode yang saya gunakan:

(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);

Ini bagus, tetapi dapatkah Anda menunjukkan bagaimana Anda akan membatasi hanya pada satu input tertentu?
jwebb

@ jwebb Tidak yakin apa maksud Anda? Kami mengganti fungsi jQuery val (). Anda mengikat pengendali acara perubahan ke input tertentu.
user2075039

Maksud saya, @ user2075039, bagaimana jika ada beberapa input pada halaman menggunakan fungsi jQuery val () dan Anda tidak ingin mengikat event handler perubahan kustom ke SEMUA dari mereka tetapi hanya salah satu dari mereka?
jwebb

@ jwebb Anda dapat memeriksa this.selectordi dalam $.fn.valfungsi utama , untuk pemilih tertentu (akan tergantung pada apa yang digunakan untuk pemilih). Ini adalah yang terbaik yang saya temukan untuk melakukan ini hanya untuk bidang tertentu, satu-satunya masalah adalah Anda harus tahu apa yang mereka gunakan untuk pemilih
sMyles

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

Ini berhasil untuk skrip saya. Saya punya 3 kombo & ikat dengan acara chainSelect, saya harus memberikan 3 nilai dengan url & default pilih semua drop down. Saya menggunakan ini

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

Dan acara pertama berhasil.


10
Saya harap, Anda tidak pernah melakukan ini di dunia nyata. Tidak perlu dikatakan bahwa $ _GET ['apa pun'] tidak dapat dipercaya.
Denis V

1

Jika Anda baru saja menambahkan opsi pilih ke formulir dan Anda ingin memicu acara perubahan, saya telah menemukan setTimeout diperlukan jika tidak, jQuery tidak mengambil kotak pilih yang baru ditambahkan:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.