Tim G
Tim G

Reputation: 1822

jQuery preventDefault() doesn't work like I expect - is this a jQuery Bug?

This is simplified code to exactly reproduce a problem I'm having with jQuery.

I would expect it to cancel the original click, then trigger the click event again which in turn would cause the browser to load the href of the url.

<script type="text/javascript">
$( function()
{
    var confirmed = false;
    $('a').click( function( event )
    {
        if ( confirmed == false )
        {
            event.preventDefault();
            confirmed = true;
            $(event.target).trigger( 'click' );
        }
    });
});

</script>

Original Question Here

I do not want to change window.location. I want to trigger so that any event handlers that have been bound to the click event will fire too. It just so happens that I also want the browser to follow the link.

Upvotes: 1

Views: 1165

Answers (6)

s4y
s4y

Reputation: 51685

.trigger('click') won’t trigger the browser’s default action — it will just trigger jQuery event handlers bound to that event on that element.

Take a look at this answer — you need to create and fire a click event yourself. Here’s the code from that answer:

function fireEvent(obj,evt){
    var fireOnThis = obj;
    if( document.createEvent ) {
      var evObj = document.createEvent('MouseEvents');
      evObj.initEvent( evt, true, false );
      fireOnThis.dispatchEvent( evObj );

    } else if( document.createEventObject ) {
      var evObj = document.createEventObject();
      fireOnThis.fireEvent( 'on' + evt, evObj );
    }
}

Upvotes: 2

Coronus
Coronus

Reputation: 587

How about doing something like creating a link offscreen that would handle the final click? That way, you can prevent the click of the original link, handle the code, then proceed to trigger the click of the hidden copy.

Upvotes: 0

user1093284
user1093284

Reputation:

I'll simply write while I analyse, hoping it'll be easy to follow and easy to compare to your code. Kick me when I can optimize/enhance my replies in any way.

checking - part 1

Move the "preventDefault" outside of the "if" statement! If you don't move it outside of the "if", the code will skip the "preventDefault" if confirmed == true.

  <script type="text/javascript">
  $( function()
  {
      var confirmed = false;
      $('a').click( function( event )
      {
          event.preventDefault();                  
          if ( confirmed == false )
          {
              confirmed = true;
              $(event.target).trigger( 'click' );
          }
      });
  });
  </script>

checking - part 2

Besides that, I'm wondering about the existence of "var confirmed" in general. The code would also work flawless without it since you're not using the confirmed variable in the function anywhere else...

  <script type="text/javascript">
  $( function()
  {
      $('a').click( function( event )
      {
          event.preventDefault();                  
          $(event.target).trigger( 'click' );
      });
  });
  </script>

checking - part 3

Knowing you can replace the trigger with a simple click, did you try that?

 <script type="text/javascript">
  $( function()
  {
      $('a').click( function( event )
      {
          event.preventDefault();                  
          $(event.target).click();
      });
  });
  </script>

checking - part 4

If the click still fails on the target element, it's definitely time to inspect (using "FireBug on Firefox" or alike) if "event.target" holds an object at all. You never know...

checking - part 5

One more thing: I don't see any Document Ready checking, so I hope you've put that script at the end of your file, right before the "</body>" tag. If you load it in the "<head>" without checking Document Ready, it might happen that javascript tries to bind the event to an element that is yet to be loaded into the dom... which would be like throwing feathers against a 9 Inch steel plate... nothing will happen. ;)

that's all

That's all that comes to mind as an answer to your question. One of them could fix the issue you're having. At least, that's what I hope. These little snippets here at stackoverflow leave massive probabilities related to what we don't see. It's hard to be sure what might be missing when you don't have the "complete view". ;)

Upvotes: 0

Ken Redler
Ken Redler

Reputation: 23943

It looks like you have one state where you want to inhibit the default action (and update a flag), and another state where you simply want the default action to apply. Wouldn't removing the else case entirely do the trick? With no preventDefault() the default click action will still run.

Edit: Pointy's answer now shows your code updated similarly.


Edit: I'm still not entirely sure what you're going for, but if for some reason you must trigger manually, one way to prevent a stack overflow due to recursion would be to assign a custom event (i.e., not click), and then always suppress the default action. Then in your conditional, either do or don't fire the custom event.

So, something like this (untested):

$('a')
  .bind('fancyclick', function () { // Your special click logic
    changeStatusOf( confirmed );
    doCrazyStuff();
    location.replace( $(this).attr('href') ); // or whatever
  })
  .click( function (e) {
    e.preventDefault(); // Always suppress natural click
    if ( confirmed ){
      $(this).trigger('fancyclick'); // Fire the special click
    }
  });

Upvotes: 0

Pointy
Pointy

Reputation: 413720

Your event handler will always be run when you trigger a "click" event, and before the default behavior happens. So no, it's not a bug.

edit — If you want the default action to happen when the element is clicked and your various conditions are satisfied, just return from your handler.

$('a').click( function( event )
{
    if ( confirmed == false )
    {
        event.preventDefault();
        confirmed = true;
    }
    else
        return;
});

When your handler returns, the browser will carry on with the default behavior.

edit again — and of course if you want to simply carry out programmatically the default action of an <a> tag with an "href" attribute, it's just:

   window.location = $(element).attr('href');

No need for a "click" event at all.

Upvotes: 2

Ecropolis
Ecropolis

Reputation: 2025

preventDefault() doesn't cancel the jquery bound click action; it cancels the 'default' click action that is inherent to an anchor tag. unbind() is the proper function for canceling any action/function that is bound to an object.

Upvotes: 0

Related Questions