views:

8009

answers:

9

I am trying to make a form with some dynamic behavior. Specifically, I have my inputs in divs, and I would like to make it so when the user clicks anywhere in the div, the input is selected. I was using JQuery 1.2.6 and everything worked fine.

However, I upgraded to JQuery 1.3.2 and I am getting some strange behavior. When I click on any of the inputs, I get a delay before it is selected. My Firefox error console gives me several "too much recursion" errors, from within the JQuery library. I tried the page in Internet Explorer 7 and got an error saying "Object doesn't support this property or method".

Am I doing something wrong, or is this a bug in JQuery? Does anyone know a way to fix this behavior, without going back to the old version? I am using Firefox 3.0.7 in case that matters. Here is a simple example I made to illustrate the problem:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>quiz test</title>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
</head>
<body>
<div class='question'>Favorite soda?
    <div><input type='radio' name='q' value='A' id='a'><label for='a'>Coke</label></div>
    <div><input type='radio' name='q' value='B' id='b'><label for='b'>Pepsi</label></div>
    </div>
<script type="text/javascript">
$(function() {
    $(".question div").click(function() {
     $(this).children("input").click();
    });
});
</script>
</body></html>
+6  A: 
<script type="text/javascript">
$(function() {
    $(".question div").click(function() {
        var radio = $(this).children("input")[0];
                radio.checked = !radio.checked;
    });
});
</script>
Ionuț G. Stan
Thanks for the fast response. I tried using focus() and I don't get the error, but clicking in the div no longer selects the input like it does with click().
mikez302
What do you mean? What's the difference?
Ionuț G. Stan
Sorry, I didn't noticed they where radio buttons.
Ionuț G. Stan
+4  A: 

ya, click event bubbles up.. so when you raise $(this).children("input").click(), you are raising $(".question div").click() again, and so on.

grilix
I thought the problem had to do with the new bubbling behavior. However, I tried calling event.stopPropagation() in my handler and I had the same problem. I also tried return false and I still had the problem.
mikez302
+3  A: 

Why do you need to do this if you are using <label for=""> already? Clicking on the label should activate the radio control anyway.

[Edit:] Following up on your comment, you can do it this way:

Make the label display as a block element, apply all styles you have used for the div wrapping the field.

.question label { display:block }

and then use this layout. You can get rid if the divs too.

<label><input type="radio">Coke</label>
<label><input type="radio">Pepsi</label>
Chetan Sastry
I am actually using this as part of a more complicated layout. The label doesn't quite take up the whole div, I couldn't do it with labels alone, and I want the input to be selected if the user clicks anywhere in the div.
mikez302
it's the better solution.
grilix
I tried making the label block, but it didn't come up quite the way I wanted. I could probably fix it if I fool around with the CSS, but I am wondering if there is a quick way to make it work like it did before, but with the new version of JQuery.
mikez302
+1 : This is the correct way to solve it. Don't reinvent the wheel... The main advantage is that this works even without javascript! It is much worthy to deal with the CSS than with "unnecessary" javascript problems. If it is not exactly as it was then you may need to revise your CSS rules and perhaps rearrange them. You should mark Chetan answer as the solution. BTW. This also applies to newer versions of JQuery.
lepe
A: 

I dont remember about how to check radios with jQuery, but could be like this:

<script type="text/javascript">
$(function() {
    $(".question div").click(function() {
        $(this).children("input").checked(true);
// or
        $(this).children("input").checked= true;
    });
});
</script>
grilix
You had a good idea, although your syntax was a little off. I tried this and it worked. $(function() { $(".question div").click(function() { $(this).children("input").attr("checked", true); }); });Thank you.
mikez302
I said, I don't remember that XD.. :)
grilix
A: 

I know this may be not the answer at all, but i am writing it as it happened to me before: It gave me “too much recursion” error while i was using jquery and prototype in the same project and also this may happen with ajax.net with jquery, so make sure that there is no conflict between libraries if you are using more than one.

Amr ElGarhy
A: 

Only fire click() when the event's target is the div, ie

$(function() {
    $(".question div").click(function(event) {
        if($(event.target).is('div'))
            $(this).children("input").click();
    });
});
Christoph
A: 

Thank you all. I tried grillix's idea of setting the checked attribute, although I had to fix up the syntax a little bit. Here is what I did:

$(this).children("input").attr("checked", true);

It works, but I am still curious as to why my previous way stopped working with JQuery 1.3.2. I know about the changes in event bubbling behavior, but why can't I fix that by calling "event.stopPropagation()" or "return false" within my callback?

mikez302
@mikez302: when you call stopPropagation(), the event has already bubbled up to the div; you'd have to add an onclick-handler to the button and the label and stop the propagation there; also, retrning false is equivalent to preventDefault(), not stopPropagation()
Christoph
ps: your solution works with radio buttons, but will fail for checkboxes
Christoph
Thank you. This new behavior is a bit strange, but I'm getting used to it now.
mikez302
It's the standard event flow: http://www.w3.org/TR/DOM-Level-3-Events/events.html#Events-flow ; event capture isn't supported in IE, though
Christoph
A: 

The problem (as grilix said) is the event "bubbling up" the DOM, so, there's an easy solution to that, you just need to cancel that bubble effect.

Bubble refers to (plain english) an event being triggered on ALL the elements that are affected because of it's position within the document. So, in your example, the "click" event is received by (in this order) the BODY, then the parent (.question) DIV, then the other DIV and finally by the INPUT.

To do that bubble cancel, you can go the jQuery way by calling the stopPropagation method within your callback function, like this:

$(function() {
    $(".question div").click(function(event) {
        $(this).children("input").click();
        event.stopPropagation();
    });
});

The plain javascript way would require you to use the cancelBubble method, but I guess it is outside the scope of your question.

Greetings, Manolo

Manoloweb