делегирование событий jQuery не работает на jQuery UI datepicker

Я пытаюсь остановить конкретное событие click от пузырьков в document-root, что в результате закрывает одно из моих всплывающих окон. Мне нужно прекратить бурление события и body или html мои единственные варианты, чтобы перехватить и остановить его.

всплывающее окно выбора даты генерируется на лету, поэтому я не могу использовать прямое событие на .ui-icon элемент, поэтому я зарегистрировал событие делегата на body элемент, чтобы остановить его от пузырения.

(function ($) {
    $(function () {
        $('body').on('click', '.ui-icon', function (e) {
            e.stopPropagation();
        });
    });
})(jQuery);

удивительно регистрации прямое событие body элемент и проверка цели события работает просто отлично.

(function ($) {
    $(function () {
        $('body').on('click', function (e) {
            if ($(e.target).is('.ui-icon')) {
                e.stopPropagation();
            }
        });
    });
})(jQuery);

Я действительно в недоумении, почему предыдущий не работает там, где делает позже, оба они должны делать то же самое. Что я упускаю? Возможно, это связано с перекомпозицией jQuery datepicker (весь его блок содержимого перестраивается при навигации) до того, как событие достигнет тела (но это не имеет смысла)?

фрагмент с проблемой добавлен ниже. Я просто хочу стрелки (навигация datepicker), чтобы остановить пузырение на уровне документа / корня (который закрывает мое всплывающее окно), и поскольку datepicker добавляется к телу, единственными доступными точками перехвата являются body/html.

$(function() {
  let popup = $('#some-popup').addClass('visible');
  let input = $('#some-date');
  let toggler = $('#toggler');

  // binding popup
  toggler.on('click', function(e) {
    e.stopPropagation();
    popup.toggleClass('visible');
  });

  // initializing jQuery UI datepicker
  input.datepicker();

  // closing popup on document clicks other than popup itself
  $(document).on('click', function(e) {
    let target = $(e.target);

    if (target.is('.ui-icon, .ui-datepicker-prev, .ui-datepicker-next')) {
      console.warn('shouldn't have reached this, got: ' + target.attr('class'));
    }

    if (!(target.is('#some-popup'))) {
      popup.removeClass('visible');
    }
  });

  // trying to prevent click from reaching document
  $('body').on('click', '.ui-icon, .ui-datepicker-prev, .ui-datepicker-next', function(e) {
    e.stopPropagation();
  })
});
#some-popup {
  padding: 15px 25px;
  background: #000;
  color: #fff;
  display: none;
  max-width: 200px;
}

#some-popup.visible {
  display: block;
}

#toggler {
  margin-bottom: 10px;
}
<head>
  <link href="https://code.jquery.com/ui/1.11.4/themes/black-tie/jquery-ui.css" rel="stylesheet">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>

<body>

  <div id="some-popup">
    This is the popup
  </div>
  <button type="button" id="toggler">Show/Hide Popup</button>
  <form>
    <label for="some-date">The Date-Picker</label>
    <input id="some-date" onclick="event.stopPropagation();" />
  </form>
</body>

1 ответов


событие делегата не срабатывает, потому что при нажатии на стрелки сначала запускается событие click кнопки со стрелкой, где jquery-ui-datepicker удаляет весь элемент календаря из body элемент и генерирует новый календарь для предыдущего / следующего месяца.

вы можете проверить, удаляется ли элемент или нет, проверив, имеет ли элемент какой-либо родитель <body> tag i.e путем проверки длины closest('body').

    $('body').on('click', function (e) {
        if ($(e.target).is('.ui-icon')) {
            console.log($(e.target).closest('body').length);
            // Prints 0 i.e this element is not a child of <body>
        }
    });

чтобы запустить событие делегата, цель элемент должен быть дочерним элементом элемента, связанного с событием, иначе jQuery не инициирует событие. Следующая демонстрация подтверждает это.

$(function() {
  $('.a').on('click', function() {
    console.log('Direct Event');
  })
  $('.a').on('click', '.b,.c', function(e) {
    console.log('Delegate Event');
  })
  $('.b').on('click', function() {
    console.log('datepicker arrow event');
    if($('input').is(':checked')) $(this).remove();
  })
});
.a {
  padding: 20px;
  background: #ffc55a;
  text-align: center;
}
.b {
  margin-top: 5px;
  padding: 5px;
  background: #7ddbff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="a">
  This is the parent element (Delegate Bound Element)
  <div class="b">
    This is the Arrow element of date-picker (Delegate Target)<br>
    Click on it to see how many events fire
  </div>
</div>
<input type="checkbox" checked> Remove On<br>
With Remove Off 3 events fire<br>
With Remove On 2 events fire, Delegate event does not fire<br>