12

Possible Duplicate:
JQuery $(#radioButton).change(…) not firing during de-selection

I have the following HTML/jQuery:

<input id="rb1" type="radio" name="rb" checked="true">
<input id="rb2" type="radio" name="rb">


$("#rb2").change(function () {
    if ($(this).is(":checked")) {
         alert('checked');
    }
    else {
        alert('unchecked');
    }
});

When my rb2 radio button is unselected by selecting rb1, the change event does not fire. Why is this? Is it possible to get this working without changing my selector to match both inputs and then looking at the ID?

Fiddle: http://jsfiddle.net/4uRWR/

Community
  • 1
  • 1
Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
  • 3
    'cause change events only fire for radios being checked? – Fabrício Matté Jan 15 '13 at 22:19
  • 2
    Seems odd that it wouldn't care about unselecting. I mean... that's a change isn't it? – Abe Miessler Jan 15 '13 at 22:20
  • Not in the W3C spec as far as I'm aware. I'll dig it up in a bit. – Fabrício Matté Jan 15 '13 at 22:21
  • It is easy to workaround though if you simply query all radios with the same name and trigger the change event on them manually. – Fabrício Matté Jan 15 '13 at 22:21
  • The answer and a solution can be found here: http://stackoverflow.com/questions/5176803/jquery-radiobutton-change-not-firing-during-de-selection – ohaleck Jan 15 '13 at 22:21
  • Use a class on the group, not an ID. – Diodeus - James MacFarlane Jan 15 '13 at 22:21
  • Radio options are displayed in groups and so it is assumed that you bind handler to the group and not single element. The change is triggered only after the element gains the focus.. in case of uncheck, the element never gains focus. A bug report associated with this behavior https://bugzilla.mozilla.org/show_bug.cgi?id=363693 – Selvakumar Arumugam Jan 15 '13 at 22:22
  • you could just change `change` to click, therefore it will fire every time you click on the radio button, and then you can check if it is checked or not... – ryanc1256 Jan 15 '13 at 22:25
  • 2
    @ryanc1256 But he isn't clicking on rb2, he's clicking on rb1 – Kevin B Jan 15 '13 at 22:25
  • You'll have to associate a change handler to all radios by using a name/class selector, so this is basically a duplicate of @ohaleck's linked post. – Fabrício Matté Jan 15 '13 at 22:26
  • Ok, voting to close then. – Abe Miessler Jan 15 '13 at 22:29
  • @KevinB oh, i didn't really read the question in vast detail, I just skim read it.. Thanks for pointing this out – ryanc1256 Jan 15 '13 at 22:30
  • You asked for a reason for why it doesn't happen though, guess I'll try to put up an answer for that as no one addressed the reason directly. – Fabrício Matté Jan 15 '13 at 22:30
  • 3
    Oh never mind, @AlienHoboken did address it. But to extend it a little further, see [ref](http://www.w3.org/TR/html401/interact/scripts.html#adef-onchange): "The `onchange` event occurs when a control loses the input focus *and* its value has been modified since gaining focus." - as the input loses its `checked` state without gaining focus, a change event is not fired. This is the standard behavior for input of type text, I'm not sure whether this is the same for radios but it is how browsers implemented it. – Fabrício Matté Jan 15 '13 at 22:36

4 Answers4

13

The change event only gets sent when you actually modify the item itself. When you click the other radio, you aren't modifying it. A fix would be to watch the change event on every input:radio, then just check the state of the relevant radio button:

$("input:radio").change(function () {
if ($("#rb2").is(":checked")) {
             alert('checked');
    }
    else {
        alert('unchecked');
    }
});

http://codepen.io/AlienHoboken/pen/akwjB

AlienHoboken
  • 2,750
  • 20
  • 23
  • 5
    *"Is it possible to get this working without changing my selector to match both inputs and then looking at the ID"* – Kevin B Jan 15 '13 at 22:24
  • 1
    @KevinB: [voila](http://stackoverflow.com/a/14349004/1081234) – Oleg Jan 15 '13 at 23:41
7

Listen for change on every input related to your group of radios and then check if a specific one is selected.

$("input[name=rb]").change(function () {
    if ($('#rb2').is(":checked")) {
        alert('checked');
    } else {
        alert('unchecked');
    }
});

http://jsfiddle.net/4uRWR/2/

Robin Drexler
  • 4,307
  • 3
  • 25
  • 28
  • 2
    *"Is it possible to get this working without changing my selector to match both inputs and then looking at the ID"* – Kevin B Jan 15 '13 at 22:25
  • This gets pretty unwieldy when you have 10 radio buttons, and even more so when the number of buttons is dynamic. – Bob Ray Jul 01 '18 at 04:38
3

You can artificially trigger a "change" on radio buttons from the same group so that the original bound handler would get picked up and output "unchecked". The trick is to avoid being stuck in an infinite loop by recursively re-triggering the event, we can avoid that by ignoring artificial events that lack the originalEvent property:

$("input[type=radio]").on("change", function (e) {
  var $this = $(this);

  //all inputs with the same name
  var $targetInputSelector = $("input[name=" + $this.attr("name") + "]");

  //check if the handler was fired "naturally"
  //if yes, trigger the change handler "artificially" for inputs with the same name
  if (e.hasOwnProperty('originalEvent')) {
    //exclude the element that was changed "naturally"
    //from the subset of all the elements with the same name
    $targetInputSelector.not($this).triggerHandler("change");
  }
});

This code works when added on top of your current handler and satisfies the without changing my selector to match both inputs and then looking at the ID criteria ;)

http://jsfiddle.net/a73tn/24/

Oleg
  • 24,465
  • 8
  • 61
  • 91
0

I sorta ran into this issue a few days ago. Instead of listening for an individual click on a radio button, I listen for a click on the <ul> I have them in and then call this function to check if one has been selected.

// Iterate over the radio group and determine if one of them is selected
function loopRadBtns(btnGroup)
{
    var isChecked = false;

    btnGroup.find('input[type="radio"]').each(function()
    {
        if($(this).attr('checked'))
        {
            isChecked = true;
        }
    });
    return isChecked;
}
Matt Whitehead
  • 1,743
  • 3
  • 19
  • 34