How to trigger an event after using event.preventDefault()

JqueryJquery Events

Jquery Problem Overview


I want to hold an event until I am ready to fire it e.g

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

   // do lots of stuff

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

}

Is there an equivalent to the run() function described above?

Jquery Solutions


Solution 1 - Jquery

Nope. Once the event has been canceled, it is canceled.

You can re-fire the event later on though, using a flag to determine whether your custom code has already run or not - such as this (please ignore the blatant namespace pollution):

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');
});

A more generalized variant (with the added benefit of avoiding the global namespace pollution) could be:

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);
    }
}

Usage:

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

Bonus super-minimalistic jQuery plugin with Promise support:

(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 (workResult && $.isFunction(workResult.then))
            {
                workResult.then(successfullyCompleted);
            }
            else
            {
                successfullyCompleted();
            }
        });
  
        return this;
    };
}(jQuery));

Usage:

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

Solution 2 - Jquery

A more recent version of the accepted answer.

Brief version:

$('#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 */
    }

});



A good use case for something like this is where you may have some legacy form code that works, but you've been asked to enhance the form by adding something like email address validation before submitting the form. Instead of digging through the back-end form post code, you could write an API and then update your front-end code to hit that API first before allowing the form to do it's traditional POST.

To do that, you can implement code similar to what I've written here:

$('#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();

    }

});

Solution 3 - Jquery

You can do something like

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

Solution 4 - Jquery

Override the property isDefaultPrevented like this:

$('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);
}

IMHO, this is most complete way of retriggering the event with the exactly same data.

Solution 5 - Jquery

A more recent answer skillfully uses jQuery.one()

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

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

https://stackoverflow.com/a/41440902/510905

Solution 6 - Jquery

It is possible to use currentTarget of the event. Example shows how to proceed with form submit. Likewise you could get function from onclick attribute etc.

$('form').on('submit', function(event) {
  event.preventDefault();
  
  // code
  
  event.currentTarget.submit();
});

Solution 7 - Jquery

Just don't perform e.preventDefault();, or perform it conditionally.

You certainly can't alter when the original event action occurs.

If you want to "recreate" the original UI event some time later (say, in the callback for an AJAX request) then you'll just have to fake it some other way (like in vzwick's answer)... though I'd question the usability of such an approach.

Solution 8 - Jquery

The approach I use is this:

$('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
});

Solution 9 - Jquery

as long as "lots of stuff" isn't doing something asynchronous this is absolutely unneccessary - the event will call every handler on his way in sequence, so if theres a onklick-event on a parent-element this will fire after the onclik-event of the child has processed completely. javascript doesn't do some kind of "multithreading" here that makes "stopping" the event processing neccessary. conclusion: "pausing" an event just to resume it in the same handler doesn't make any sense.

if "lots of stuff" is something asynchronous this also doesn't make sense as it prevents the asynchonous things to do what they should do (asynchonous stuff) and make them bahave like everything is in sequence (where we come back to my first paragraph)

Solution 10 - Jquery

The accepted solution wont work in case you are working with an anchor tag. In this case you wont be able to click the link again after calling e.preventDefault(). Thats because the click event generated by jQuery is just layer on top of native browser events. So triggering a 'click' event on an anchor tag wont follow the link. Instead you could use a library like jquery-simulate that will allow you to launch native browser events.

More details about this can be found in this link

Solution 11 - Jquery

Another solution is to use window.setTimeout in the event listener and execute the code after the event's process has finished. Something like...

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

> I use 0 for the period since I do not care about waiting.

Solution 12 - Jquery

you can use it with Timer or without Timer.

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

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

    x.preventDefault()

    // Ajax or nay Code

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

})

Solution 13 - Jquery

I know this topic is old but I think I can contribute. You can trigger the default behavior of an event on a specific element any time in your handler function if you already know that behavior. For example, when you trigger the click event on the reset button, you actually call the reset function on the closest form as the default behavior. In your handler function, after using the preventDefault function, you can recall the default behavior by calling the reset function on the closest form anywhere in your handler code.

Solution 14 - Jquery

If this example can help, adds a "custom confirm popin" on some links (I keep the code of "$.ui.Modal.confirm", it's just an exemple for the callback that executes the original action) :

//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();
			}
		);
	}
);

Solution 15 - Jquery

If you add an event listener to a form and await its submission then after checking what you need to check you can call the submission of the form with .submit ie

const checkoutForm = document.getElementById('checkout-form');
const cart = {};
if (checkoutForm) {
	checkoutForm.addEventListener('submit', e => {
		e.preventDefault();
		if(JSON.stringify(cart) === '{}'){
			console.log('YOUR CART IS EMPTY')
			alert('YOUR CART IS EMPTY');
			return;
		}
		else{
			checkoutForm.submit();
		}
	})
}

<form id="checkout-form" action="action-page" method="post">
  <input type="text" name="name" />
  <button>Submit</button>
</form>

With this you can solve the form submission issues like checking for the strength of the password and checking whether all fields needed have the correct data

Solution 16 - Jquery

Here is my old idea of using preventDefault and trigger "click" inside. I just pass argument "prevent" to the function:

$(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;
                }
            }
        });
    }

});

I hope someone will find it useful

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMazatecView Question on Stackoverflow
Solution 1 - JqueryvzwickView Answer on Stackoverflow
Solution 2 - JqueryCory DanielsonView Answer on Stackoverflow
Solution 3 - JqueryRafael OliveiraView Answer on Stackoverflow
Solution 4 - JqueryTomislav SimićView Answer on Stackoverflow
Solution 5 - JqueryOranges13View Answer on Stackoverflow
Solution 6 - JquerySalvis BlūzmaView Answer on Stackoverflow
Solution 7 - JqueryLightness Races in OrbitView Answer on Stackoverflow
Solution 8 - JqueryHokusaiView Answer on Stackoverflow
Solution 9 - JqueryoeziView Answer on Stackoverflow
Solution 10 - JqueryMiguel CarvajalView Answer on Stackoverflow
Solution 11 - JqueryagelbessView Answer on Stackoverflow
Solution 12 - JqueryMahdi SaneipourView Answer on Stackoverflow
Solution 13 - JqueryPatrikView Answer on Stackoverflow
Solution 14 - JqueryRonan KerdudouView Answer on Stackoverflow
Solution 15 - JqueryLive Software DeveloperView Answer on Stackoverflow
Solution 16 - JqueryRadosław AndraszykView Answer on Stackoverflow