Klik jQuery menyala dua kali saat mengklik label

114

Saya menggunakan jQuery untuk membuat tombol radio khusus dan saya punya masalah. Saat mengklik label yang terkait dengan radio, peristiwa klik akan menyala dua kali, jika saya hanya mengklik di radio itu sendiri, itu berfungsi dengan baik (sebenarnya bukan radio yang saya klik tetapi div yang membungkus seluruh input dan label). Ini kodenya:

HTML:

 <div id="box">
     <asp:RadioButtonList ID="RadioButtonList1" runat="server">
         <asp:ListItem>RADIO1</asp:ListItem>
         <asp:ListItem>RADIO2</asp:ListItem>
         <asp:ListItem>RADIO3</asp:ListItem>
     </asp:RadioButtonList>
</div>

jQuery:

<script type="text/javascript">
       $(function () {
            $('#box').find('input:radio').each(function (i) {

            var input = $(this);
            // get the associated label using the input's id
            var label = $('label[for=' + input.attr('id') + ']');
            // wrap the input + label in a div
            $('<div class="custom-radio"></div>').insertBefore(input).append(label, input);

            var wrapperDiv = input.parent();

            // find all inputs in this set using the shared name attribute
            var allInputs = $('input[name=' + input.attr('name') + ']');

            // necessary for browsers that don't support the :hover pseudo class on labels
            label.hover(

            function () {
                $(this).addClass('hover');
            }, function () {
                $(this).removeClass('hover checkedHover');
            });

            //bind custom event, trigger it, bind click,focus,blur events
            wrapperDiv.bind('updateState', function () {
                if ($(this)[0].children[1].checked) {
                    allInputs.each(function () {
                        var curDiv = $('div > label[for=' + $(this).attr('id') + ']').parent();
                        curDiv.removeClass('custom-radio-checked');
                        curDiv.addClass('custom-radio');
                    });
                    $(this).toggleClass('custom-radio custom-radio-checked');
                }
                else {
                    $(this).removeClass('custom-radio-checked checkedHover checkedFocus');
                }

            })
            .trigger('updateState')
            .click(function () { console.log('click'); })
            .focus(function () {
                label.addClass('focus');
            }).blur(function () {
                label.removeClass('focus checkedFocus');
            });
        }); 
       });
   </script>

Apakah ada solusi untuk perilaku ini?

nada
sumber

Jawaban:

130

Coba tambahkan:

evt.stopPropagation();
evt.preventDefault();

ke .bind () atau .click (), mana saja yang Anda lihat. Juga, tambahkan parameter evtke fungsi, sepertifunction(evt) {...

Yordania
sumber
9
mengapa ini terjadi?
chovy
8
Karena ada item bersarang. Setiap item dalam hierarki akan menampilkan acara tersebut.
Yordania
7
Jika Anda menggunakan ini untuk kotak centang, ini juga diperlukan bagi saya untuk mengaktifkan masukan agar benar-benar diperiksa:jQuery('input').prop('checked', true);
David Sinclair
6
return false;setara dengan `evt.stopPropagation (); evt.preventDefault (); ( di jQuery )
basil
193

Saya mencoba menambahkan solusi di atas dengan menambahkan:

evt.stopPropagation();
evt.preventDefault();

tapi tidak berhasil. Namun menambahkan ini:

evt.stopImmediatePropagation();

memecahkan masalah! :)

N3da
sumber
6
Saya tidak tahu mengapa, tapi apa yang Anda katakan sepertinya berhasil untuk kode saya. Terima kasih!
shaosh
8
Sempurna. Ini bekerja dengan baik! Meskipun evt.stopPropagation(); evt.preventDefault();tidak; 't
James111
1
hanya ini yang berhasil untuk saya, saya telah mencoba fungsi lain tanpa hasil
gardarvalur
1
Jawaban ini menyelamatkan hidup saya! Terima kasih: D
Bluetree
1
Ini adalah jawaban untuk saya!
Dyluck
73

Ikat acara klik ke masukan, bukan ke label. Ketika label diklik - peristiwa akan tetap terjadi karena, seperti yang disebutkan Dustin, klik pada label memicu klik pada input. Ini akan memungkinkan label untuk mempertahankan fungsi normalnya.

$('input').click();

Dari pada

$('label').click();
dougmacknz
sumber
10
Solusi ini juga berfungsi jika markup Anda menggunakan teknik label-wrapping-the-input, dan hanya menyelamatkan kewarasan saya: o)
Whelkaholism
4
Anda harus mengikatnya changebahkan pada tombol radio karena teks label dapat diklik - mereka tidak selalu mengeklik tombol radio itu sendiri.
chovy
2
Jika menggunakan label > inputpengaturan Bootstrapesque , ini adalah jawabannya, bukan jawaban. Menambahkan evt.stopPropagation()atau evt.preventDefault()ke kode Anda, meskipun efektif, adalah peretasan yang harus dihindari jika solusi yang tepat jauh lebih bersih dan efisien.
elPastor
wow wow hanya wow, saya menghabiskan hampir beberapa hari untuk mencari tahu, akhirnya ini membantu dan terima kasih banyak atas penjelasannya
opensource-developer
ini menyelamatkan hariku!
gab06
11

Jika Anda mencoba menggunakan penampung luar sebagai elemen klik, Anda juga dapat membiarkan peristiwa menggelembung secara alami dan menguji elemen yang diharapkan di penangan klik Anda. Skenario ini berguna jika Anda mencoba memberi gaya zona klik unik untuk formulir.

<form>
<div id="outer">
    <label for="mycheckbox">My Checkbox</label>
    <input type="checkbox" name="mycheckbox" id="mycheckbox" value="on"/>
</div>
</form>
<script>
$('#outer').on('click', function(e){
    // this fires for #outer, label, and input
    if (e.target.tagName == 'INPUT'){
        // only interested in input
        console.log(this);
    }
});
</script>
tobius
sumber
1
Ini berfungsi untuk saya karena saya masih ingin tombol radio dipilih. Saya hanya tidak ingin event handler melakukan semuanya dua kali.
chovy
1
Ini tidak mengizinkan anak-anak untuk dipilih. BTW, opsi yang lebih baik untuk mencapai fungsi yang sama adalahif (e.target == e.currentTarget) {}
Chicken Soup
9

Untuk memperbaikinya dengan cara mudah, hapus atribut "for" pada label. Klik pada label juga akan memicu klik pada elemen terkait. (yang dalam kasus Anda mengaktifkan peristiwa klik dua kali.)

Semoga berhasil

Dustin
sumber
Memang solusi cepat. Orang mungkin berpendapat bahwa itu mengacaukan markup, tetapi saya akan membantah bahwa tujuan atribut "untuk" adalah propogasi peristiwa. Jadi jika Anda menggunakan mekanisme lain (jquery) maka dengan segala cara singkirkan "untuk".
Chris Harrington
5

Saya biasanya menggunakan synthax ini

.off('click').on('click', function () { console.log('click'); })

dari pada

.click(function () { console.log('click'); })
Dalibor
sumber
5

Jawaban terbaik tersembunyi di dalam komentar:

Anda harus mengikatnya changebahkan pada tombol radio karena teks label dapat diklik - mereka tidak selalu mengeklik tombol radio itu sendiri. - chovy 12 Desember '13 pukul 1:45

Ini biola menggambarkan bahwa semua lainnya solusi - stopPropagation, stopImmediatePropagation, preventDefault, return false- baik perubahan apa-apa atau menghancurkan kotak centang / fungsi radio). Ini juga menggambarkan bahwa ini adalah masalah JavaScript vanilla, bukan masalah jQuery.

EDIT: Solusi kerja lain yang baru saja saya temukan di utas lain adalah mengikat onclickke input daripada label. Biola diperbarui .

WoodrowShigeru
sumber
2

Saya telah mencoba dengan menambahkan solusi.

evt.stopPropagation();
evt.preventDefault();

tapi tidak berhasil.

Dengan menambahkan

evt.stopImmediatePropagation();

memecahkan masalah! :)

Janki Moradiya
sumber
1

Masalah dengan e.preventDefault (); apakah itu menghentikan klik label dari memeriksa tombol radio.

Solusi yang lebih baik adalah dengan menambahkan pemeriksaan cepat "dicentang" seperti ini:

$("label").click(function(e){
  var rbtn = $(this).find("input");
  if(rbtn.is(':checked')){
  **All the code you want to have happen on click**
  }
)};
yoshyosh
sumber
1
Solusi yang lebih ringkas adalah dengan hanya menggunakan .mouseup daripada .click
yoshyosh
1
Solusi ini tidak berfungsi jika kode Anda juga akan memungkinkan pengguna untuk membatalkan pilihan tombol radio. Kebakaran ganda menyebabkan masalah serius dalam kasus ini.
Johncl
1

Masalah saya sedikit berbeda, karena evt.stopPropagation();evt.preventDefault();tidak berhasil untuk saya, saya hanya menambahkan return false;di bagian akhir, lalu berhasil.

$("#addressDiv").on("click", ".goEditAddress", function(event) {
    alert("halo");
    return false;
});
GMsoF
sumber
1

Dalam kasus saya, masalahnya adalah saya memiliki acara klik dalam suatu fungsi dan fungsi tersebut dijalankan dua kali .... setiap eksekusi fungsi tersebut membuat acara klik baru. - Telapak tangan -

setelah memindahkan peristiwa klik di luar fungsi, semuanya bekerja seperti yang diharapkan! :)

FalcoB
sumber
0

Coba letakkan tag masukan Anda di luar elemen pemicu, karena tag label mengemulasi klik, jadi Anda akan selalu memiliki lebih dari satu panggilan.

Benjamin
sumber
0

Saya memiliki masalah yang sama karena saya telah menempatkan radio saya di dalam label seperti ini dengan penangan yang terpasang ke radio_div. Menghapus label bertingkat memperbaiki masalah.

<div id="radio_div">
    <label>
       <input type="radio" class="community_radio" name="community_radio" value="existing">
           Add To Existing Community
    </label>
</div>
shaw2thefloor
sumber
0

Label memicu radio / kotak centang untuk dicentang.

if ($(event.target).is('label')){
    event.preventDefault();
}

Ini mencegah terutama label untuk memicu perilaku ini.

Kevin.B
sumber
0

Klik pada label dengan atribut for = "some-id" memicu klik baru, tetapi hanya jika target ada dan merupakan masukan. Saya tidak dapat menyelesaikannya dengan sempurna dengan e.preventDefault () atau hal-hal seperti itu jadi saya melakukannya seperti ini:

Misalnya, jika Anda memiliki struktur ini dan menginginkan acara dengan mengklik .some-class

<div class="some-class">
    <input type=checkbox" id="the-input-id" />
    <label for="the-input-id">Label</label>
</div>

Apa yang berhasil adalah:

$(document)
    .on('click', '.some-class', function(e) {
        if(
            $(e.target).is('label[for]')
            &&
            $('input#' + $(e.target).attr('for')).length
        ) {
            // This will trigger a new click so we are out of here
            return;
        }

        // else do your thing here, it will not get called twice
    })
;
Julesezaar
sumber