63

This question is for the purposes of developing jQuery plugins and other self-contained JavaScript snippets that don't require modifying other script files for compatibility.

We all know that event.preventDefault() will prevent the default event so we can run a custom function. But what if we want to simply delay the default event before invoking it? I've seen various, case-specific ninja tricks and workarounds to re-invoke the default action, but like I said, my interest is in a universal way to re-trigger the default, and not deal with default triggers on a case-by-case basis.

$(submitButton).click(function (e) {

    e.preventDefault();

    // Do custom code here.

    e.invokeDefault(); // Imaginary... :(
});

Even for something as simple as form submission, there seems to be no universal answer. The $(selector).closest("form").submit() workaround assumes that the default action is a standard form submission, and not something wacky like a __doPostBack() function in ASP.NET. To the end of invoking ASP.NET callbacks, this is the closest I've come to a universal, set-it-and-forget-it solution:

$(submitButton).click(function (e) {

    e.preventDefault();

    // Do custom code here.

    var javascriptCommand = e.currentTarget.attributes.href.nodeValue;
    evalLinkJs(javascriptCommand);
});


function evalLinkJs(link) {
    // Eat it, Crockford. :)
    eval(link.replace(/^javascript:/g, ""));
}

I suppose I could start writing special cases to handle normal links with a window.location redirect, but then we're opening a whole new can of worms--piling on more and more cases for default event invocation creates more problems than solutions.

So how about it? Who has the magic bullet that I've been searching for?

Jake
  • 4,829
  • 2
  • 33
  • 44
  • 2
    I don't really get what you're trying to do... doesn't the event handler code run *before* the default action occurs (e.g. a `submit` event handler's code will run before the form is actually submitted... isn't that what you're trying to achieve?) – James Allardice Oct 11 '11 at 21:41
  • 3
    Is your custom code asynchronous? this might explain why you feel you need such a method, but even having that imaginary method won't solve your problem. – agradl Oct 11 '11 at 21:48
  • 1
    You definitely need to be more clear about what you want. If you want to run code within the handler, that code runs before the "default" behavior anyway. – Mike Edwards Oct 11 '11 at 21:56
  • `preventDefault` prevents the default action. If you want the default action to occur, don't prevent it. Seems pretty obvious. – Lightness Races in Orbit Oct 11 '11 at 22:00
  • 1
    maybe @Jake means something more like [this](http://stackoverflow.com/questions/18050538/invoke-the-default-action-of-a-specific-event-on-an-object) – Hashbrown Aug 05 '13 at 04:22

5 Answers5

14

Don't call preventDefault() in the first place. Then the default action will happen after your event handler.

Ben
  • 10,056
  • 5
  • 41
  • 42
  • 16
    This is the right answer as long as you're not needing to do the default handling asynchronously after your custom handling. – Jacob Oct 11 '11 at 22:10
  • No true in my `copy` handler, I need to return `true` for the text to be copied. Do nothing or return falsy values also don't work. But that's not the OP's question. – Hp93 Dec 02 '20 at 12:03
  • also not true in my case, where I need to pass a keydown event off to an `input` element while it's not focused. Being able to manually invoke the default keydown handler would be the most simple, straightforward way to allow the input to receive keystrokes even when it's not focused. I think dispatchEvent might be what I'm looking for – Braden Best Sep 22 '22 at 18:21
13

Take a look at this one:

You could try

if(!event.mySecretVariableName) {
   event.preventDefault();
} else {
   return; // do nothing, let the event go
}

// your handling code goes here
event.originalEvent.mySecretVariableName = "i handled it";

if (document.createEvent) {
   this.dispatchEvent(event.originalEvent);
} else {
    this.fireEvent(event.originalEvent.eventType, event.originalEvent);
}

Using this answer: How to trigger event in JavaScript? and the jQuery event reference: http://api.jquery.com/category/events/event-object/

Tag the event object you receive so if you receive it again you don't loop.

Community
  • 1
  • 1
Mike Edwards
  • 3,742
  • 17
  • 23
4

This should work. I've only tested in firefox though.

<html>
<head>
<script>
    window.addEventListener("click",handleClick,false);
    function handleClick(e){
        if (e.useDefault != true){
            alert("we're preventing");
            e.preventDefault();
            alert(e.screenX);
            //Firing the regular action
            var evt = document.createEvent("HTMLEvents");
            evt.initEvent(e.type,e.bubbles,e.cancelable);
            evt["useDefault"] = true;
            //Add other "e" attributes like screenX, pageX, etc...
            this.dispatchEvent(evt);
        }
        else{
            alert("we're not preventing");
        }
    }
</script>
</head>
<body>

</body>
</html>

Of course, you'd have to copy over all the old event variables attributes too. I just didn't code that part, but it should be easy enough.

Azmisov
  • 6,493
  • 7
  • 53
  • 70
  • 2
    +1 This is the correct approach. You should attempt to create the correct type of event - see https://developer.mozilla.org/en-US/docs/DOM/document.createEvent – chowey Mar 29 '13 at 04:32
  • `initEvent` is deprecated now. – schmijos Aug 23 '22 at 14:01
2

It's not possible like JamWaffles has already proven. Simple explanation why it's impossible: if you re-trigger the default action your event listener intercept again and you have an infinite loop.

And this

click(function (e) {
    e.preventDefault();
    // Do custom code here.
    e.invokeDefault(); // Imaginary... :(
});

is the same like this (with your imaginary function).

click(function (e) {
    // Do custom code here.
});

It seems that you want to manipulate the url of your clicked element. If you do it like this it just works fine. Example.

styrr
  • 829
  • 4
  • 9
  • i'm not sure this makes sense, especially if you think of `preventDefault` as doing (pseudocode) `e.shouldExecuteDefault = false` - note that the default action happens after all event handlers. with this analogy `invokeDefault()` would just do `shouldExecuteDefault = true` again – somebody Jun 02 '23 at 02:50
0

I needed to disable a button after click and then fire the default event, this is my solution

$(document).on('click', '.disabled-after-submit', function(event) {
    event.preventDefault();
    $(event.currentTarget).addClass('disabled');
    $(event.currentTarget).removeClass('disabled-after-submit');
    $(event.currentTarget).click();
    $(event.currentTarget).prop('disabled', true);
});
Tomáš Tibenský
  • 811
  • 11
  • 20