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>
Eric Belair
sumber

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();
pengguna113716
sumber
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.

David mengatakan mengembalikan Monica
sumber
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');
Eric Belair
sumber
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.

Marnix
sumber
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/

Alireza Fattahi
sumber
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');
codingrhythm
sumber
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);
pengguna2075039
sumber
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.

Prashant Patil
sumber
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);
Dave Hilditch
sumber