Как продолжить распространение события после отмены? - PullRequest
56 голосов
/ 18 октября 2011

Когда пользователь нажимает на определенную ссылку, я хотел бы предоставить ему диалог подтверждения. Если они нажимают «Да», я хотел бы продолжить исходную навигацию. Один улов: мое диалоговое окно подтверждения реализовано путем возврата объекта jQuery.Deferred, который разрешается только тогда, когда / если пользователь нажимает кнопку Да. Таким образом, в основном диалог подтверждения является асинхронным.

Так что в основном я хочу что-то вроде этого:

$('a.my-link').click(function(e) {
  e.preventDefault(); e.stopPropogation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      //continue propogation of e
    })
})

Конечно, я мог бы установить флажок и повторно щелкнуть, но это чертовски грязно. Любой естественный способ сделать это?

Ответы [ 7 ]

11 голосов
/ 19 октября 2011

К моему удивлению, ниже приведены фрагменты кода, который фактически работал в Chrome 13.

function handler (evt ) {
    var t = evt.target;
    ...
    setTimeout( function() {
        t.dispatchEvent( evt )
    }, 1000);
    return false;
}

Это не очень кросс-браузер, и, возможно, будет исправлено в будущем, потому что это похоже на угрозу безопасности, imho.

И я не знаю, что произойдет, если вы отмените распространение событий.

3 голосов
/ 12 мая 2015

Если я правильно понимаю проблему, думаю, вы можете просто обновить событие, чтобы оно стало исходным событием в том закрытии, которое у вас там есть.Так что просто установите e = e.originalEvent в функции .done.

https://jsfiddle.net/oyetxu54/

MyApp.confirm("confirmation?")
.done(function(){ e = e.originalEvent;})

- это скрипка с другим примером (держите консоль открытой, чтобы вы могли видетьсообщения): это работало для меня в Chrome и Firefox

3 голосов
/ 17 мая 2012

Так я решил проблему на одном из своих проектов.Этот пример работает с некоторыми основными обработками событий, такими как щелчки и т. Д. Обработчик подтверждения должен быть привязан к первому обработчику.

0 голосов
/ 14 декабря 2018

Я отредактировал твой код. Новые функции, которые я добавил:

  1. Добавлено пространство имен для события;
  2. После нажатия на элемент событие будет удалено пространством имен;
  3. Наконец, после завершения необходимых действий в разделе «MyApp» продолжить распространение, вызывая события «щелчка» других элементов.

Код:

$('a.my-link').on("click.myEvent", function(e) {
  var $that = $(this);
  $that.off("click.myEvent");
  e.preventDefault();
  e.stopImmediatePropagation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
        //continue propogation of e
        $that.trigger("click");
    });
});
0 голосов
/ 09 августа 2017

У нас есть аналогичные требования в нашем проекте, и это работает для меня. Протестировано в Chrome и IE11.

$('a.my-link').click(function(e) {
  e.preventDefault(); 
  if (do_something === true) {
    e.stopPropogation();
    MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      do_something = false;
      // this allows user to navigate 
      $(e.target).click();
    })
  }

})
0 голосов
/ 20 мая 2015

Я решил это следующим образом:

  1. поместив прослушиватель событий на родительский элемент
  2. , удалив класс из ссылки ТОЛЬКО когда пользователь подтвердит
  3. повторным нажатиемссылка после того, как я удалил класс.

function async() {
  var dfd = $.Deferred();
  
  // simulate async
  setTimeout(function () {
    if (confirm('Stackoverflow FTW')) {
      dfd.resolve();
    } else {
      dfd.reject();
    }
  }, 0);
  
  return dfd.promise();
};

$('.container').on('click', '.another-page', function (e) {
  e.stopPropagation();
  e.preventDefault();
  async().done(function () {
    $(e.currentTarget).removeClass('another-page').click();
  });
});

$('body').on('click', function (e) {
  alert('navigating somewhere else woot!')
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="container">
  <a href="#" class="another-page">Somewhere else</a>
</div>

Причина, по которой я добавил прослушиватель событий к родителю, а не к самой ссылке, заключается в том, что событие jQuery on будет привязано к элементу, пока не будет сказано иначе.Поэтому, хотя элемент не имеет класса another-page, к нему по-прежнему подключен прослушиватель событий, поэтому для решения этой проблемы необходимо воспользоваться event delegation.

GOTCHAS этоочень основанный на состоянии.т. е. если вам нужно спросить пользователя КАЖДЫЙ ВРЕМЯ, когда он нажимает на ссылку, вам нужно будет добавить второго слушателя, чтобы снова прочитать класс another-page на этой ссылке.то есть:

$('body').on('click', function (e) {
  $(e.currentTarget).addClass('another-page');
});

примечание вы также можете удалить прослушиватель событий на container, если пользователь принимает, если вы делаете это, убедитесь, что вы используете namespace события, потому что могутбыть другими слушателями на контейнере, который вы можете случайно удалить.см. https://api.jquery.com/event.namespace/ для более подробной информации.

0 голосов
/ 18 октября 2011

Это не проверено, но может служить для вас обходным путем

$('a.my-link').click(function(e) {
  e.preventDefault(); e.stopPropogation();
  MyApp.confirm("Are you sure you want to navigate away?")
    .done(function() {
      //continue propogation of e
      $(this).unbind('click').click()
  })
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...