jQuery .one("click") on anchor wrapper leads to href not followed

Go To StackoverFlow.com

2

This is a deceptively tricky little bit of HTML/JS that has either me or jQuery thrown for a loop (my money's on me).

It's demoed in this fiddle.


...but here's the scenario. An anchor is wrapped with a span:

<span> the span
    <a onclick="alert('onclick HTML attritbute fired!')" href="http://www.href-attribute-    fired.com">the link</a>
    wraps the link
</span>

The span has a click handler that clicks the anchor. This needs to be .one() to avoid looping forever because of event bubbling (I also tried .on() and .off() to short circuit the loop with the same result - see fiddle).

$('a').click(function() {
    alert("jQuery click fired!");
});

$('span').one("click", function() {
    alert('(span clicked, let us see what other events fire...)');
    $(this).find('a').click();
});

What you'll notice when you click on the link itself is that:

  1. onclick HTML attritbute fired!
  2. jQuery click fired!
  3. (span clicked, let us see what other events fire...)
  4. onclick HTML attritbute fired!
  5. jQuery click fired!
  6. the href is followed

It loops through the JS events an extra time because of the event bubbling up to the span, which is a little goofy and inelegant but totally expected and makes sense to me. The key part here is that after all the JS events are through, the href is followed.

When you click on the outer span, this is the order of events:

  1. (span clicked, let us see what other events fire...)
  2. jQuery click fired!
  3. onclick HTML attritbute fired!
  4. ... {crickets!?!} ....

Even though the anchor's JS click events have fired, the href is never followed.


I'm guessing that .one() doesn't unbind the click event for the span until the second time through, after bubbling up from the anchor, and at at that point, the event propagation completely dies. Since the href is not followed until all click events are finished, when the signal dies at the span the anchor doesn't know to fire the go-to-href event.

...but is that really what happens? What gives?

What is a better way to approach this problem (I'd like to avoid JS pulling off the href and setting window.location manually for a variety of reasons)?

2012-04-05 15:20
by peteorpeter
Mixing jQuery-assigned event handlers with handlers defined in HTML attributes is generally a really bad idea - Pointy 2012-04-05 15:22
This reminds me of a question that came up a few days ago: http://stackoverflow.com/questions/10000852/click-does-not-work-with-link - Chris Laplante 2012-04-05 15:23
Have you tried a much simpler example where a click event handler on one element calls click() on an anchor element? I have, and it doesn't follow the link - Graham Clark 2012-04-05 15:29
@GrahamClark Just did after seeing Pointy's answer. Palm-smacking in progress - peteorpeter 2012-04-05 15:32


4

The link is followed in the first instance (when you click it directly) because that's the way <a> tags work, and none of your handlers asks that the default behavior be cancelled.

Triggering a "click" via jQuery on an <a> tag explicitly does not follow the link; that's just how jQuery works.

2012-04-05 15:25
by Pointy
+1 Wow, I can't believe I didn't know that! All the other stuff was a total red herring. FWIW I updated the fiddle with a button showing your point - peteorpeter 2012-04-05 15:31
So, is there a way to explicitly trigger link hrefs (that's prettier than setting window.location) - peteorpeter 2012-04-05 15:34
The jQuery documentation for .trigger() is really lousy. If you want to duplicate what happens when a real "click" happens on an <a>, you have to grab the "href" property and assign it to window.location.href - Pointy 2012-04-05 15:35
+1: This perfectly coincides with this question from a few days ago - Chris Laplante 2012-04-05 15:36
Many thanks! (In my exact use case, this is bad news. I have a variety of anchor actions I'll need to account for - a simple href, an onlick attribute to run, sometimes there is a jQuery click handler and the href is "javascript:void". Just about every link action our app uses shows up in this list. It won't be pretty! - peteorpeter 2012-04-05 15:43
Ads