24

I'm currently upgrading my application to use jQuery 1.6.1 (previously using 1.4.4) and found that now the .click() event automatically triggers a .change() event as well.

I created a simple example here: http://jsfiddle.net/wDKPN/

Notice if you include 1.4.4 the .change() function will not fire when the .click() event is triggered. But when switching to 1.6, the .change() event is fired when .click() is triggered.

Two questions:

  1. Is this a bug? It seems that programmatically triggering .click() shouldn't also fire other events (for example, it would seem wrong to also automatically fire .blur() and .focus(), to help "mimic" a user's click).

  2. What is the proper way for me to bind a change() event and then trigger both a click() and change() event for that element? Do I simply call .click(), and rely on the fact that .change() will also fire?

    $('#myelement').change(function() {
         // do some stuff
    });
    
    $('#myelement').click(); // both click and change will fire, yay!
    

In my old code I'm using this pattern to initialize some checkboxes (and their checked states and values) after an ajax call:

    $('#myelement').change(function() {
         // do some stuff including ajax work
    }).click().change();

But in 1.6.1 my logic fires twice (once for .click() and once for .change()). Can I rely on just removing the .change() trigger and hope that jQuery continues to behave this way in future versions?

L84
  • 45,514
  • 58
  • 177
  • 257
Jared Cobb
  • 5,167
  • 3
  • 27
  • 36
  • 2
    Even though this is a very good observation, I would call it more of a 'fix' than a 'bug'. Clicking the checkbox makes it change state, hence there is a completely valid reason for it to trigger change event as a consequence. To me it's strange that it wasn't doing that before (and there was [a thread on SO](http://stackoverflow.com/questions/2161213/why-is-onchange-on-a-checkbox-not-fired-when-the-checkbox-is-changed-indirectly) for that matter). – mkilmanas Jun 14 '11 at 20:39
  • Certainly, I think I can agree this was on purpose and probably not a bug. I hope it stays this way for upgrades though... And can't we argue then for other events? For example, can we rephrase this as saying, "If a user **clicks** a checkbox they **must** have changed it too". Can we also say, "If a user **clicks** a checkbox it **must** have received focus". But the .focus() event doesn't fire automatically with .click() the way .change() does. – Jared Cobb Jun 14 '11 at 20:51
  • interesting facts, did yopu made some tests on IE (6?) as I remember some strange behaviors with checkboxes/jQuery and event chain? Did you check as well with triggerHandler('click'), as the doc said "The .triggerHandler() method does not cause the default behavior of an event to occur (such as a form submission)", so does this make the chained change run now? – regilero Jun 14 '11 at 21:52
  • @regilero, I just tested in IE7/8/9 (I don't care about 6 right now) and to make matters worse, IE7/8 **don't** automatically fire the .change() event with jQuery 1.6.1. IE9 behaves like FF4 / Chrome12 / Safari. So at the very least we have an inconsistency with lesser versions of IE. – Jared Cobb Jun 14 '11 at 22:14
  • we're just talking checkboxes here right? SELECT list seems to require binding to both 'click' and 'change' if you desire a click to trigger your event – Simon_Weaver Jan 10 '13 at 10:13

4 Answers4

3

Best way to do this is:

$('#myelement').bind('initCheckboxes change', function() {
     // do some stuff including ajax work
}).trigger('initCheckboxes');

To do your initialization stuff you just bind to it a custom event, which you trigger it the first time the page loads. This, no one will take away from you on any versions.

Whereas change event, I believe, will continue to be there on all versions, because it has been for so long, and it just works nicely that way.

In the end, this is a happy ending story, because the custom event initCheckboxes will fire just once on page load and change event will always listen and fire on change state.

Shef
  • 44,808
  • 15
  • 79
  • 90
  • Awesome. I was too deep into the code to think big picture. This also resolves the fact that IE7/8 behave differently than all the others. And it's upgrade proof (so if they decide to stop calling .change() automatically from .click() it doesn't matter. Finally, in my HTML I'm just going to create my checkboxes with checked="checked" so that on init they'll be seen as "checked" (which resolves my other requirement from my comment to @kwicher below). THANK YOU! – Jared Cobb Jun 15 '11 at 17:40
  • triggerHandler may be better for most situations? http://api.jquery.com/triggerHandler vs. http://api.jquery.com/trigger – Simon_Weaver Jan 10 '13 at 10:18
3

I would say this was a bug in jQuery 1.4.4. Removing the jQuery event handlers and using standard addEventListener produces the same result as jquery 1.6.1.

http://jsfiddle.net/jruddell/wDKPN/26/

window.count = 0;

document.getElementById('mycheckbox').addEventListener('change', function() {
    window.count++;
    jQuery('#output').append('I fired: ' + window.count + ' times<br />');
});

document.getElementById('mycheckbox').click();

Also I would use triggerHandler to specifically invoke a jQuery event handler. If you want the event model to determine which handlers to call, then use click, change etc.

Josiah Ruddell
  • 29,697
  • 8
  • 65
  • 67
2

Forget about the click event for checkboxes. The change event handles everything.

$('#myelement').change(function() {
    // do some stuff
});
$('#myelement').trigger('change');

See for yourself: http://jsfiddle.net/zupa/UcwdT/ (This demo is set to jQuery 1.8 but works in 1.6 as well.)

zupa
  • 12,809
  • 5
  • 40
  • 39
1

I think you can make it work for both jQuery 1.4.4 and 1.6 implementations by putting change() within click handler and then triggering the click.

$('.myelement').click(function(){
 $('.myelement').change();   
 alert($(this).val());
});
$('.myelement').trigger('click');

Have a look there for simple example.

George Cummins
  • 28,485
  • 8
  • 71
  • 90
kwicher
  • 2,092
  • 1
  • 19
  • 28
  • This might work for the simple use case I presented... But the purpose of binding to the .change() event is that the **state** of the checkbox itself is different when inside a .click() event vs a .change() event. I created another example here: http://jsfiddle.net/hLVaC/1/ (notice that inside a click event, the actual state of the checkbox isn't updated yet when called programatically, and in my case I'm using ajax calls to dynamically determine the checkbox checked state upon initialization). – Jared Cobb Jun 15 '11 at 16:17
  • This will attach `change` event endlessly. – Shef Jun 15 '11 at 16:31
  • @Shef - Correct, I just noticed that in my sandbox testing :) – Jared Cobb Jun 15 '11 at 16:35