Menjalankan Javascript Saat Widget Ditambahkan di Backend

20

Saya memiliki widget yang memiliki kontrol javascript yang menyertainya.

Jika widget hadir saat halaman admin widget dimuat, kontrol berfungsi dengan benar.

Ketika saya menambahkan widget baru, mereka tidak berfungsi dengan benar, saya mendapatkan markup, tetapi tidak ada efek javascript yang berlaku.

Jika saya menyimpan widget baru, ketika formulir dimuat kembali, kontrol dibuat dengan benar dan sekarang berfungsi.

Menyegarkan halaman juga memperbaiki masalah, tetapi hanya untuk widget yang ada. Widget baru masih memiliki masalah ini.

Secara khusus saya menjalankan pilih pada input pilih pada titik-titik ini:

  • dokumen siap
  • Lengkap ajax

Saya telah memverifikasi bahwa kode saya dijalankan pada setiap acara seperti yang diinginkan, tetapi hasilnya tidak seperti yang diharapkan.

Berikut ini adalah plugin pengujian yang menunjukkan masalah ini:

https://gist.github.com/Tarendai/8466299

Anda akan melihat saya memiliki penghitung yang bertambah dengan setiap elemen pilih yang ditemukannya dapat dikonversi.

Catatan:

  • Ketika halaman widget dimuat, saya bisa melihat penghitung meningkat di konsol JS seperti yang diharapkan
  • Ketika saya menambahkan widget baru, kode dijalankan, namun gagal menemukan elemen pilih yang dapat dijalankan, seperti yang ditunjukkan oleh found.length menjadi 0. Ini tidak boleh terjadi, karena setiap widget baru dari jenis itu harus memiliki elemen pilih
  • elemen pilih memiliki kelas untuk mengidentifikasi mereka, kelas ini dihapus setelah perpustakaan pilihize diterapkan untuk mencegah duplikasi dan pemrosesan ulang pada widget yang ada.
  • Sebelum menggunakan selectize, saya menggunakan Select2, yang memiliki masalah yang sama
  • Mengomentari kode AJAX, saya berharap widget baru memiliki input pilih standar. Mereka tidak. Saya tidak tahu mengapa ini terjadi

Jadi, bagaimana cara membuat kontrol pilih bekerja tanpa menyuruh pengguna menyegarkan / mengklik simpan sebelum membuat perubahan?

Tom J Nowell
sumber
Ini masalah delegasi acara. Anda perlu melihat menggunakan .on()metode jQuerys . Yang mengharuskan Anda untuk mengikat suatu acara ke dokumen. Namun acara apa yang akan tepat saya tidak yakin sekarang. Pada akhirnya itu karena binding asli Anda mewakili versi awal DOM ketika halaman dimuat dan sebagian besar tidak mengetahui elemen baru (konten widget) yang ditambahkan melalui ajax. Semoga itu akan mengarahkan Anda ke arah yang benar, jika tidak saya bisa menjawab lebih baik ketika saya sedang bekerja.
Inilah yang saya harapkan, dan mengapa saya menambahkan jQuery( document ).ajaxStop( function() {bagian tersebut sehingga saya bisa menginisialisasi kontrol di widget yang baru dimuat. Namun jika saya menghapus baris itu saya akan berharap widget baru untuk memiliki input pilih HTML standar, tetapi mereka tidak = s
Tom J Nowell
Sebagai @ aaron-holbrook berkomentar, pendekatannya adalah yang paling bersih dengan menggunakan widget-updateddan widget-addedacara. Saya juga ingin menekankan, dalam kode @michaeljames, penggunaan elemen id #widgets-right. Pastikan untuk menggunakannya untuk menargetkan elemen widget aktif di dalam kode JS Anda, jika tidak, Anda bisa mendapatkan elemen duplikat karena kode Anda juga dapat memilih elemen widget tidak aktif tersembunyi di sisi kiri layar (dan elemen-elemen itu dikloning ketika widget ditambahkan).
Julien

Jawaban:

12

Kabar baik,

Saya sudah memperbaikinya.

Permintaan maaf karena kehilangan inti Anda dalam komentar awal saya dan memberi Anda jawaban yang sudah Anda terapkan. Itu akan mengajarkan saya untuk menjawab di ponsel saya saat di kereta!

Penggunaan ajaxstop Anda benar. Neraka JS untuk sebagian besar berfungsi dengan benar, Anda bisa melihat gaya css diinisialisasi dan perubahan di DOM.

Masalahnya sebenarnya terletak pada pemilih Anda.

Ini karena konten widget tidak dimuat melalui ajax, bahkan itu mengkloningnya dari kolom sebelah kiri di mana ia disembunyikan dan kemudian menembakkan panggilan ajax untuk menyimpan posisi widget di kolom sebelah kanan. Ini menjelaskan mengapa ajaxstop berfungsi sebagai suguhan, bahkan konten berpikir dikloning. Namun, karena ada versi tersembunyi dari widget di kolom sebelah kiri, JS Anda adalah instantiating untuk itu. Dengan demikian, ketika Anda menyeretnya ke kolom sebelah kanan, Anda mendapatkan klon acak dari widget tersembunyi.

Jadi, Anda perlu memilih satu di sisi kiri. Di bawah ini adalah kode yang diperbaiki:

<script>
jQuery( document ).ready( function( $ ) {
    function runSelect() {
        var found = $( '#widgets-right select.testselectize' );
        found.each( function( index, value ) {

            $( value ).selectize();
                .removeClass( 'testselectize' )
                .addClass( 'run-' + window.counter );

            console.log( $val );
            window.counter++;
        } );
    }

    window.counter = 1;

    runSelect();

    $( document ).ajaxStop( function() {
        runSelect();
    } );
} );
</script>
kaisar
sumber
Astaga, aku harus menguji ini <3
Tom J Nowell
Solusi yang sangat elegan untuk sakit kepala utama!
bosco
3
Saya akan menyarankan agar tidak menjalankan pada setiap acara 'ajaxStop' dan sebagai gantinya menyarankan menggunakan pada acara 'ditambahkan widget' serta 'diperbarui widget'.
Tyrun
16

Seperti @ aaron-holbrook berkomentar pendekatan yang lebih bersih akan dilakukan:

jQuery(document).on('widget-updated widget-added', function(){
    // your code to run
});

Dalam banyak kasus, Anda juga ingin menjalankan JS ketika halaman dimuat serta ketika widget diperbarui. Anda dapat melakukannya seperti ini.

function handle_widget_loading(){
   // your code to run
}
jQuery(document).ready( handle_widget_loading );
jQuery(document).on('widget-updated widget-added', handle_widget_loading );

Cukup tempel di sini untuk referensi karena jawabannya jauh lebih mudah untuk menemukan komentar itu

chifliiiii
sumber
2
mungkin sebaiknya menggunakan jQuery sebagai ganti $
Mark Kaplun