views:

598

answers:

2

This question is similar to my last question about "too much recursion" errors in jQuery, but involving live handlers. I have one element within another. Both of them have custom event handlers with the same name. The outer element has a traditional handler and the inner element has a live handler. When I try to trigger the event on the outer element, my browser pauses for a while, then I get an error saying "too much recursion".

I read on the live handler documentation page that I can prevent bubbling of a live handler by returning false within the handler function. However, I tried this and it doesn't seem to make a difference. Either way, the outer function seems to somehow be called many times when I am trying to call it only once.

How can I fix this? Is it possible to have handlers with the same name like this, or do I have to come up with different names? You can test the problem using this code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html><head>
<title>live event handler test</title>
</head>
<body>
<div id="outer">
    <div id="inner">
    </div>
</div>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$("#outer").bind("test", function() {
    $("#inner").trigger("test");
});

$("#inner").live("test", function() {
    return false;
});

$(function() {
    $("#outer").trigger("test");
});
</script>
</body></html>
A: 

It seems like the combination of live and bind for a custom event has a bug in it? Not quite sure what is going on actually. If you only use live it works:

$("#outer").live("test", function() {
    console.log("outer");
    $("#inner").trigger("test");
});

$("#inner").live("test", function() {
     console.log("inner");
    return false;
});

$(function() {
    $("#outer").trigger("test");
});

Haven't dug into the source too much but it seems like bind ignores the return value of the function.

seth
Really? I tried changing the "test" names to "click" and I am getting the exact same error.
mikez302
Yeah, I was wrong. Updated my answer.
seth
+1  A: 

Look at #outer's callback:

$("#outer").bind("test", function() {
    $("#inner").trigger("test");
});

You are triggering "test"on #inner, but #inner is a child of #outer, so the event "bubbles up" to #outer and the whole process repeats itself (until it blows up).

Edit: as @Seth points out, if you use live() on both #outer and #inner it works. That's because "return false;" works like event.stopImmediatePropagation() in that case. Likewise, if you use bind() on both it also works. That's because "return false;" works like event.stopPropagation() in that case.

However you are mixing both and using bind on #outer and live on #inner. Net effect is that triggering your event as I pointed out will never execute your live handler (i.e. return false never gets executed) because it is bound to the document, and the event never get a chance to bubble up to the document due to the stack overflow.

Edit 2:

Is there a way to prevent the bubbling on the inner event? (using live()?)

Nope. See http://stackoverflow.com/questions/1122375/jquery-event-stoppropagation-seems-not-to-work a better explanation.

Crescent Fresh
Why does the event on #inner bubble up to #outer? Isn't the "return false" statement supposed to prevent that?
mikez302
Why is there a stack overflow? If the live handler never gets executed, I don't see why the outer function would get called more than once.
mikez302
@mikez302: `trigger` bubbles. Simple as that. Remove `live` and the problem still exists. `live` has nothing to do with it. The wording of my last paragraph is confusing the issue I think. The problem is still what I state in the first paragraph.
Crescent Fresh
Is there a way to prevent the bubbling on the inner event?
mikez302
@mikez302: yes, use `bind()` for `#inner` rather than `live()`.
Crescent Fresh
Is there a way to do this for live events?
mikez302
@mikez302: Nope. See http://stackoverflow.com/questions/1122375/jquery-event-stoppropagation-seems-not-to-work
Crescent Fresh