Legend
Legend

Reputation: 116810

How can I attach a listener to multiple radio buttons?

I have three radio buttons like this:

<input type="radio" name="P_1" value="1">Yes</input>
<input type="radio" name="P_1" value="2">No</input>

<input type="radio" name="P_2" value="1">Yes</input>
<input type="radio" name="P_2" value="2">No</input>

<input type="radio" name="P_3" value="1">Yes</input>
<input type="radio" name="P_3" value="2">No</input>

I am trying to add a listener to each of these radio buttons so that I will be notified when they change. I am doing something like this:

for (var i = 1; i <= 3; i++) {
            $("input[name='P_" + i + "']").live('change', function () {
                doProcessing("P_" + i, $("input[name='P_" + i + "']:checked").val());
            });
}

However, this does not seem to work. It calls doProcessing with i set to 4 because that is the value of i at the end of the for loop. What is the correct way of adding an event handler in my case?

Upvotes: 2

Views: 7778

Answers (3)

zzzzBov
zzzzBov

Reputation: 179046

As with any asynchronous iterative value, you need to close over the value in the loop:

for (i = 0; i < 3; i++) {
    (function(i){
        ...your code here...
    }(i));
}

By the time the event handler is called, the value of the i variable will have reached its maximum value (in this case 3).

An alternative means of passing data to each handler, would be to use the data parameter of the on method:

for (i = 0; i < 3; i++) {
    $(...selector...).on('change', null, {i:i}, function (e) {
        //access the i value with: e.data.i
    });
}

It would probably be better to simply check for the right value within the handler, and use a class to attach the event:

$(document).on('change', '.someClass', function (e) {
    var i,
        $this;
    $this = $(this);
    i = $(this).attr('name').substr(2);
    i = parseInt(i, 10);
    ...your code here...
});

If you can't change the markup, then you can use '[name^="P_"]' in place of '.someClass'.

Upvotes: 2

Joe
Joe

Reputation: 6416

Try

$('input:radio').on('change', function(){
    //access value of changed radio group with $(this).val()
});

Or, if you're using < jQuery 1.7

$('input:radio').live('change', function(){
    //do stuff with $(this).val()
});

Upvotes: 8

bfavaretto
bfavaretto

Reputation: 71908

You have to use a closure that will remember the index value on each step. Here is one of the many possible ways to do that:

for (var i = 1; i <= 3; i++) {
   $("input[name='P_" + i + "']").live('change', createListener(i));
}

function createListener(index) {
    return function() {
        doProcessing("P_" + index, $("input[name='P_" + index + "']:checked").val());
    }
}

Upvotes: 1

Related Questions