jQuery Click срабатывает дважды при нажатии на ярлык

114

Я использую jQuery для создания настраиваемых переключателей, и у меня проблема. При нажатии на метку, связанную с радио, события щелчка запускаются дважды, если я нажимаю только на само радио, оно работает нормально (ну, на самом деле это не радио, которое я нажимаю, а div, который обертывает весь ввод и метку). Вот код:

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>

Есть ли какое-нибудь решение для такого поведения?

тон
источник

Ответы:

130

Попробуйте добавить:

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

в .bind () или .click (), в зависимости от того, что вы видите. Также добавьте параметр evtк функции, напримерfunction(evt) {...

Иордания
источник
9
почему это происходит?
chovy
8
Потому что есть вложенные элементы. Каждый элемент в иерархии всплывает в виде события.
Jordan
7
Если вы используете это для флажка, это также было необходимо для меня, чтобы я мог действительно проверить ввод:jQuery('input').prop('checked', true);
Дэвид Синклер
6
return false;эквивалентен `evt.stopPropagation (); evt.preventDefault (); ( в jQuery )
Василий
193

Я попытался добавить решение выше, добавив:

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

но не сработало. Однако добавив это:

evt.stopImmediatePropagation();

решил проблему! :)

N3da
источник
6
Не знаю почему, но то, что вы сказали, похоже, работает для моего кода. Спасибо!
shaosh
8
Отлично. Это сработало! Хотя evt.stopPropagation(); evt.preventDefault();не
сделал
1
только это сработало для меня, другие функции я пробовал безуспешно
gardarvalur
1
Этот ответ спас мне жизнь! Спасибо: D
Bluetree
1
Это был ответ для меня!
Dyluck
73

Привяжите событие щелчка к вводу, а не к метке. Когда метка нажата - событие все равно произойдет, потому что, как упоминал Дастин, щелчок по метке вызывает щелчок по вводу. Это позволит этикетке сохранить свою нормальную функциональность.

$('input').click();

Вместо того

$('label').click();
Dougmacknz
источник
10
Это решение также работает, если ваша разметка использует технику label-wrapping-the-input и просто спасла мне рассудок: o)
Whelkaholism
4
вы должны выполнить привязку changeдаже к радиокнопке, поскольку текст метки кликабелен - они не всегда нажимают сам радиокнопку.
chovy
2
Если вы используете label > inputнастройку Bootstrapesque , это ответ, а не ответ. Добавление evt.stopPropagation()или evt.preventDefault()в ваш код, хотя и является эффективным, - это хитрость, которой следует избегать, когда правильное решение намного чище и эффективнее.
elPastor 03
вау, вау, просто вау, я потратил почти пару дней на то, чтобы разобраться, наконец, это помогло, и большое спасибо за объяснение,
разработчик с открытым исходным кодом
это спасло мне день!
gab06
11

Если вы пытаетесь использовать внешний контейнер в качестве элемента щелчка, вы также можете позволить событиям всплывать естественным образом и проверить ожидаемый элемент в обработчике щелчка. Этот сценарий полезен, если вы пытаетесь создать уникальную зону щелчка для формы.

<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>
Тобиус
источник
1
Это сработало для меня, поскольку я все еще хотел, чтобы переключатель был выбран. Я просто не хотел, чтобы обработчик событий делал все дважды.
chovy
1
Это не позволит выбрать детей. Кстати, лучшим вариантом для достижения той же функциональности будетif (e.target == e.currentTarget) {}
Chicken Soup
9

Чтобы исправить это простым способом, удалите атрибут «for» на этикетке. Щелчок по метке также вызовет щелчок по соответствующему элементу. (который в вашем случае дважды запускает событие click.)

Удачи

Dustin
источник
Действительно быстрое решение. Кто-то может возразить, что это портит разметку, но я бы возразил, что цель атрибута «for» - распространение событий. Так что, если вы используете другой механизм (jquery), во что бы то ни стало избавьтесь от «for».
Крис Харрингтон
5

Я обычно использую этот синтаксис

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

вместо того

.click(function () { console.log('click'); })
Далибора
источник
5

Лучший ответ скрыт внутри комментариев:

вы должны выполнить привязку changeдаже к радиокнопке, поскольку текст метки кликабелен - они не всегда нажимают сам радиокнопку. - chovy 12 дек.

Эта скрипка показывает , что все остальные решения - stopPropagation, stopImmediatePropagation, preventDefault, return false- либо изменить ничего или не уничтожить / функциональность радио флажка). Это также показывает, что это проблема обычного JavaScript, а не проблема jQuery.

РЕДАКТИРОВАТЬ: Еще одно рабочее решение, которое я только что нашел в другом потоке, - это привязать onclickк вводу, а не к метке. Обновленная скрипка .

WoodrowShigeru
источник
2

Я пробовал добавлять раствор.

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

но не сработало.

Добавляя

evt.stopImmediatePropagation();

решил проблему! :)

Янки Морадия
источник
1

Проблема с e.preventDefault (); это останавливает щелчок метки от проверки переключателя.

Лучшим решением было бы просто добавить быструю проверку «проверено», например:

$("label").click(function(e){
  var rbtn = $(this).find("input");
  if(rbtn.is(':checked')){
  **All the code you want to have happen on click**
  }
)};
Йошёш
источник
1
Еще более лаконичным решением было бы просто использовать .mouseup, а не .click
yoshyosh
1
Это решение не работает, если ваш код также позволяет пользователю отменить выбор переключателя. В этом случае двойной пожар доставляет серьезные неприятности.
Johncl
1

Моя проблема немного в другом, так как у evt.stopPropagation();evt.preventDefault();меня не работает, я просто добавляю return false;в конце, и это работает.

$("#addressDiv").on("click", ".goEditAddress", function(event) {
    alert("halo");
    return false;
});
GMsoF
источник
1

В моем случае проблема заключалась в том, что у меня было событие щелчка в функции, и функция была выполнена дважды .... каждое выполнение функции создает новое событие щелчка. - фейспалм -

после перемещения события щелчка за пределы функции все заработало, как ожидалось! :)

FalcoB
источник
0

Попробуйте поместить свой тег ввода за пределы элемента триггера, потому что тег метки имитирует щелчок, поэтому у вас всегда будет более одного вызова.

Вениамин
источник
0

У меня была такая же проблема, потому что я вложил свое радио внутри метки, как это, с обработчиком, прикрепленным к radio_div. Удаление вложенной метки устранило проблему.

<div id="radio_div">
    <label>
       <input type="radio" class="community_radio" name="community_radio" value="existing">
           Add To Existing Community
    </label>
</div>
shaw2thefloor
источник
0

Ярлык вызывает установку флажка / переключателя.

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

Это предотвращает, особенно ярлык, чтобы вызвать это поведение.

Кевин Б.
источник
0

Щелчок по ярлыку с атрибутом for = "some-id" вызывает новый щелчок, но только если цель существует и является входом. Мне не удалось решить эту проблему с помощью e.preventDefault () или тому подобного, поэтому я сделал это так:

Например, если у вас есть эта структура и вы хотите, чтобы событие при нажатии на .some-class

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

Что действительно работало:

$(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
источник