Как вызвать событие после использования event.preventDefault()

Я хочу провести мероприятие до тех пор, пока я не буду готов его запустить, например

$('.button').live('click', function(e){

   e.preventDefault(); 

   // do lots of stuff

   e.run() //this proceeds with the normal event    

}

Есть ли эквивалент run() функция описана выше?

17 ответов

Решение

Нету. Как только событие было отменено, оно отменяется.

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

var lots_of_stuff_already_done = false;

$('.button').on('click', function(e) {
    if (lots_of_stuff_already_done) {
        lots_of_stuff_already_done = false; // reset flag
        return; // let the event bubble away
    }

    e.preventDefault();

    // do lots of stuff

    lots_of_stuff_already_done = true; // set flag
    $(this).trigger('click');
});

Более обобщенный вариант (с дополнительным преимуществом предотвращения загрязнения глобального пространства имен) может быть:

function onWithPrecondition(callback) {
    var isDone = false;

    return function(e) {
        if (isDone === true)
        {
            isDone = false;
            return;
        }

        e.preventDefault();

        callback.apply(this, arguments);

        isDone = true;
        $(this).trigger(e.type);
    }
}

Использование:

var someThingsThatNeedToBeDoneFirst = function() { /* ... */ } // do whatever you need
$('.button').on('click', onWithPrecondition(someThingsThatNeedToBeDoneFirst));

Бонус супер-минималистичный плагин JQuery с Promise служба поддержки:

(function( $ ) {
    $.fn.onButFirst = function(eventName,         /* the name of the event to bind to, e.g. 'click' */
                               workToBeDoneFirst, /* callback that must complete before the event is re-fired */
                               workDoneCallback   /* optional callback to execute before the event is left to bubble away */) {
        var isDone = false;

        this.on(eventName, function(e) {
            if (isDone === true) {
                isDone = false;
                workDoneCallback && workDoneCallback.apply(this, arguments);
                return;
            }

            e.preventDefault();

            // capture target to re-fire event at
            var $target = $(this);

            // set up callback for when workToBeDoneFirst has completed
            var successfullyCompleted = function() {
                isDone = true;
                $target.trigger(e.type);
            };

            // execute workToBeDoneFirst callback
            var workResult = workToBeDoneFirst.apply(this, arguments);

            // check if workToBeDoneFirst returned a promise
            if ($.isFunction(workResult.then))
            {
                workResult.then(successfullyCompleted);
            }
            else
            {
                successfullyCompleted();
            }
        });

        return this;
    };
}(jQuery));

Использование:

$('.button').onButFirst('click',
    function(){
        console.log('doing lots of work!');
    },
    function(){
        console.log('done lots of work!');
    });

Более свежая версия принятого ответа.

Краткая версия:

$('#form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.lots_of_stuff_done ) {
        e.preventDefault();
        $.ajax({
            /* do lots of stuff */
        }).then(function() {
            // retrigger the submit event with lots_of_stuff_done set to true
            $(e.currentTarget).trigger('submit', { 'lots_of_stuff_done': true });
        });
    } else {
        /* allow default behavior to happen */
    }

});



Хороший вариант использования для чего-то подобного - это когда у вас может быть какой-то унаследованный код формы, который работает, но вас попросили улучшить форму, добавив что-то вроде проверки адреса электронной почты перед отправкой формы. Вместо того, чтобы копаться в почтовом коде серверной формы, вы можете написать API, а затем обновить свой код переднего плана, чтобы сначала использовать этот API, прежде чем позволить форме выполнять традиционный POST.

Для этого вы можете реализовать код, подобный тому, что я написал здесь:

$('#signup_form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.email_check_complete ) {

        e.preventDefault(); // Prevent form from submitting.
        $.ajax({
            url: '/api/check_email'
            type: 'get',
            contentType: 'application/json',
            data: { 
                'email_address': $('email').val() 
            }
        })
        .then(function() {
            // e.type === 'submit', if you want this to be more dynamic
            $(e.currentTarget).trigger(e.type, { 'email_check_complete': true });
        })
        .fail(function() {
            alert('Email address is not valid. Please fix and try again.');
        })

    } else {

        /**
             Do traditional <form> post.
             This code will be hit on the second pass through this handler because
             the 'email_check_complete' option was passed in with the event.
         */

        $('#notifications').html('Saving your personal settings...').fadeIn();

    }

});

Вы можете сделать что-то вроде

$(this).unbind('click').click();

Переопределить свойство isDefaultPrevented как это:

$('a').click(function(evt){
  evt.preventDefault();

  // in async handler (ajax/timer) do these actions:
  setTimeout(function(){
    // override prevented flag to prevent jquery from discarding event
    evt.isDefaultPrevented = function(){ return false; }
    // retrigger with the exactly same event data
    $(this).trigger(evt);
  }, 1000);
}

ИМХО, это наиболее полный способ перезапуска события с точно такими же данными.

Более свежий ответ умело использует jQuery.one()

$('form').one('submit', function(e) {
    e.preventDefault();
    // do your things ...

    // and when you done:
    $(this).submit();
});

/questions/26743442/jquery-zapretit-po-umolchaniyu-zatem-prodolzhit-po-umolchaniyu/26743459#26743459

Можно использовать currentTarget из event, Пример показывает, как приступить к отправке формы. Точно так же вы можете получить функцию от onclick атрибут и т. д.

$('form').on('submit', function(event) {
  event.preventDefault();

  // code

  event.currentTarget.submit();
});

Просто не выступать e.preventDefault();или выполнить это условно.

Вы, конечно, не можете изменить, когда происходит исходное событие.

Если вы хотите "воссоздать" исходное событие пользовательского интерфейса через некоторое время (скажем, в обратном вызове для запроса AJAX), то вам просто придется подделать его другим способом (как в ответе vzwick)... хотя я бы Вопрос в юзабилити такого подхода.

Подход, который я использую, заключается в следующем:

$('a').on('click', function(event){
    if (yourCondition === true) { //Put here the condition you want
        event.preventDefault(); // Here triggering stops
        // Here you can put code relevant when event stops;
        return;
    }
    // Here your event works as expected and continue triggering
    // Here you can put code you want before triggering
});

До тех пор, пока "много вещей" не делает что-то асинхронное, это абсолютно ненужно - событие будет вызывать каждый обработчик на своем пути в последовательности, поэтому, если на родительском элементе происходит событие onklick, оно будет срабатывать после onclik- Событие ребенка обработано полностью. javascript здесь не выполняет какую-то "многопоточность", что делает необходимым "остановку" обработки событий. Вывод: "приостанавливать" событие, просто чтобы возобновить его в том же обработчике, не имеет никакого смысла.

если "много вещей" является чем-то асинхронным, это также не имеет смысла, поскольку мешает асинхронным вещам делать то, что они должны делать (асинхронные вещи), и заставляет их вести себя так, как будто все в порядке (где мы возвращаемся к моему первому абзацу))

вы можете использовать его с таймером или без таймера.

const form = document.querySelector('#form');

form.addEventListener('submit', (x) => {

x.preventDefault()

// Ajax or nay Code

setTimeout(() => {
    x.target.submit();
}, 1000)

})

Принятое решение не будет работать, если вы работаете с тегом привязки. В этом случае вы не сможете снова нажать на ссылку после звонка. e.preventDefault(), Это потому, что событие click, сгенерированное jQuery, это просто слой поверх событий собственного браузера. Таким образом, запуск события click для тега привязки не будет переходить по ссылке. Вместо этого вы можете использовать библиотеку типа jquery-simulate, которая позволит вам запускать собственные события браузера.

Подробнее об этом можно узнать по этой ссылке

Другим решением является использование window.setTimeout в слушателе событий и выполнение кода после завершения процесса события. Что-то вроде...

window.setTimeout(function() {
  // do your thing
}, 0);

Я использую 0 для периода, так как меня не волнует ожидание.

если это простые вещи, ты можешь поиграть с помощью mouseenter

      $(document).on('mouseenter','.button',function(e) {
    //if class not exist yet -> do ajax
    
    //after complete add class
    $(this).addClass('ajx-event-completed');
});

$(document).on('click','.button',function(e) {
    if($(this).hasClass('ajx-event-completed')){
        //do something else
    }
    else{
        e.preventDefault();
        //we are CLOSED today! See you next week
    }
    //do more
});

Я знаю, что эта тема старая, но я думаю, что могу внести свой вклад. Вы можете в любой момент вызвать поведение по умолчанию для определенного элемента в своей функции-обработчике, если вы уже знаете это поведение. Например, когда вы запускаете событие click для кнопки сброса, вы фактически вызываете функцию сброса в ближайшей форме в качестве поведения по умолчанию. В вашей функции-обработчике после использования функции protectDefault вы можете вызвать поведение по умолчанию, вызвав функцию сброса в ближайшей форме в любом месте кода вашего обработчика.

Если этот пример может помочь, добавьте "пользовательское подтверждение popin" на некоторые ссылки (я сохраняю код "$.ui.Modal.confirm", это просто пример обратного вызова, который выполняет исходное действие):

//Register "custom confirm popin" on click on specific links
$(document).on(
    "click", 
    "A.confirm", 
    function(event){
        //prevent default click action
        event.preventDefault();
        //show "custom confirm popin"
        $.ui.Modal.confirm(
            //popin text
            "Do you confirm ?", 
            //action on click 'ok'
            function() {
                //Unregister handler (prevent loop)
                $(document).off("click", "A.confirm");
                //Do default click action
                $(event.target)[0].click();
            }
        );
    }
);

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

С его помощью вы можете решить проблемы с отправкой формы, такие как проверка надежности пароля и проверка правильности данных во всех необходимых полях.

Вот моя старая идея использования preventDefault и запуска "щелчка" внутри. Я просто передаю аргумент "предотвратить" функции:

      $(document).on('click', '.attachments_all', function(e, prevent = true){

    if(prevent){

        e.preventDefault();

        var button = $(this);
        var id = button.data('id');
    
        $.ajax({
            type: 'POST',
            url: window.location.protocol + '//' + window.location.host + path + '/attachments/attachments-in-order/' + id, 
            dataType: 'json',
            success: function(data){
                if(data.success && data.attachments){ 
                    button.trigger('click', false);
                } else {
                    swal({
                        title: "Brak załączników!",
                        text: "To zamówienie nie posiada żadnych załączników!",
                        type: "error"
                    });
                    return;
                }
            }
        });
    }

});

Надеюсь, кому-то это пригодится

Другие вопросы по тегам