Ticket #3827 (closed bug: fixed)
Checkbox state inconsistent in click event handler
| Reported by: | skorpan | Owned by: | dmethvin |
|---|---|---|---|
| Priority: | high | Milestone: | 1.9 |
| Component: | event | Version: | 1.2.6 |
| Keywords: | 1.9-discuss | Cc: | |
| Blocking: | Blocked by: |
Description
I'm not sure whether this is intended behavior or simply impossible to hack in pure JavaScript, but here goes nothing...
There is a significant difference between actually clicking an element and the triggering of the click event handlers bound to that element by JQuery. Attached to this ticket is a test script and its HTML to reproduce this "bug". What happens is:
- I click the checkbox and see "State: ON" in the Firebug console. I click it a few times to verify that the correct state is always reported.
- I click the button which in turn programmatically triggers the click event bound to the checkbox. Now the INCORRECT state is reported every time. This is probably due to the bound event handler being triggered before any internal behavior.
Attachments
Change History
comment:1 Changed 4 years ago by dmethvin
Can you explain what behavior you expected? Does it differ from raw Javascript behavior in some undesirable way? In general, all the handlers have to run before the browser's default action is taken. That's because the event handler can return false or e.preventDefault() to stop the default action.
comment:2 Changed 4 years ago by dmethvin
I did some further work on this, and I agree with your analysis. Test case attached, checked in FF3 and IE8B2. The difference is because .trigger("click") calls the handler before the checkbox native click() method. A click on the checkbox calls the checkbox native click() method; that method causes the onclick event to fire and jQuery calls the handler.
See this thread for more discussion:
http://groups.google.com/group/jquery-dev/browse_frm/thread/39c3dabc8ac3569a
Changed 4 years ago by dmethvin
-
attachment
test-3827.html
added
event handling with jQuery trigger() and DOM events
comment:4 Changed 3 years ago by dmethvin
Closed duplicate #5727 with another test case.
More info:
http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-6043025
Note: During the handling of a click event on an input element with a type attribute that has the value "radio" or "checkbox", some implementations may change the value of this property before the event is being dispatched in the document. If the default action of the event is canceled, the value of the property may be changed back to its original value. This means that the value of this property during the handling of click events is implementation dependent.
It seems like most modern browsers change the checkbox state before calling the event handler, then revert it if the default action is cancelled.
comment:5 Changed 3 years ago by dmethvin
- Summary changed from Click event triggered "too late" to Checkbox state inconsistent in click event handler
Closed duplicate #6775.
comment:6 Changed 3 years ago by dmethvin
- Status changed from new to closed
- Resolution set to wontfix
This behavior has been consistent since jQuery's first version, so there's no way we could change it without breaking significant existing code.
comment:8 Changed 2 years ago by David Sanders
If you compare jQuery's behaviour with raw JavaScript the results are opposite.
The best policy here is to fix this in the next major version of jQuery and tell people there's a BC break otherwise everyone will have to put up with annoying workarounds until the end of time.
comment:9 Changed 2 years ago by anonymous
Hey,
I was having the same issue, and found a great answer on Stack Overflow here: http://stackoverflow.com/questions/3478267/jquery-strange-behaviour-on-click-from-a-click
Basically, instead of just calling the click() method of the checkbox, you set the attribute "checked" to true or false, which checks or unchecks the box, and then manually call the event handler by using triggerHandler("click"). Here's the code that I used:
Check the box: $(this).find("input.city_selector_chk").attr('checked', 'true'); $(this).find("input.city_selector_chk").triggerHandler("click");
Uncheck the box: $(this).find("input.city_selector_chk").attr('checked', ); $(this).find("input.city_selector_chk").triggerHandler("click");
Hope this helps! Paul
comment:10 Changed 2 years ago by jitter
#8374 is a duplicate of this ticket.
comment:11 Changed 2 years ago by dmethvin
#8636 is a duplicate of this ticket.
comment:12 Changed 2 years ago by anonymous
I don't understand why this is a won't fix. Manual triggering of event is basically broken with this bug!
comment:13 Changed 20 months ago by euan.ritchie@…
Having recently discovered this issue I note that there is different behaviour between different versions of jQuery;
Given a input:checkbox that has both an inline onclick handler and a jQuery bound click handler the value of checked differs according both to how the click is triggered and what version of jQuery is in use.
Actually clicking on the element in the browser changes the checked value before the events are handled.
With jQuery 1.6.2 using $(element).trigger('click') handles the events before the checked value changes.
In jQuery 1.3.2 the behaviour is slightly different as one handler is called before the checked state changes and the other after.
So at least now the behaviour is consistent across handlers and predictable, though I think ought still be fixed. If not in a minor version change then certainly by jQuery 2.0
comment:14 Changed 18 months ago by dmethvin
#10166 is a duplicate of this ticket.
comment:15 Changed 18 months ago by dmethvin
#10005 is a duplicate of this ticket.
comment:16 Changed 18 months ago by dmethvin
#9274 is a duplicate of this ticket.
comment:17 Changed 18 months ago by dmethvin
#8885 is a duplicate of this ticket.
comment:18 Changed 18 months ago by dmethvin
#8796 is a duplicate of this ticket.
comment:19 Changed 18 months ago by dmethvin
#10827 is a duplicate of this ticket.
comment:20 Changed 13 months ago by rwaldron
#11602 is a duplicate of this ticket.
comment:21 Changed 13 months ago by anonymous
As a note to anyone else suffering with this bug, you can work around this problem by wrapping your checkbox's click event handler in setTimeout(function(){ ... }, 1);
comment:22 Changed 11 months ago by dmethvin
#11991 is a duplicate of this ticket.
comment:23 Changed 11 months ago by dmethvin
- Keywords 1.9-discuss added; click, event, trigger, checkbox, button removed
comment:24 Changed 11 months ago by derek.rosenzweig@…
I too am having issues with this. I dynamically add a new checkbox, and using delegated 'click' handler:
$('div.parent').on('click', 'input[type=checkbox].classname', function() {
if ($(this).is(':checked')) { <--- this shows opposite value when doing $(element).trigger('click');
do stuff
}
});
comment:25 Changed 11 months ago by checat
Just 2 cents.
Ideally jQuery click() and DOM click() should work identically for elements which have DOM click().
comment:26 Changed 11 months ago by coreyog@…
There have been 13 duplicate bugs posted in the past 3 years indicating many people find it should not be the way it is. Several fixes ranging from setTimeout(..., 1) to setting the checked attribute and calling the triggerHandler have been proposed but these are work arounds to account for a bug, i.e. people aren't accepting this as expected behavior. Checat makes a valid point for why expectations supports the idea that this is a bug. The cause of the problem has been pointed out by dmethvin and it honestly sounds like an easy fix.
Fixing this bug in a new release would only impact those who have legacy code referencing a constantly changing 'newest release'. Those developers should know that a constantly updated library will occasionally not only have changes, but fixes, that would impact their projects.
comment:27 Changed 11 months ago by dmethvin
Suggestions for a fix are welcome. Please submit a patch.
comment:28 Changed 9 months ago by dmethvin
- Priority changed from minor to high
- Milestone changed from 1.3 to 1.9
Okay, let's try one last time, because this one bothers me too. I think this can be fixed with the 1.7 special event hooks if we assume that click is a DOM event and don't let it flow through the normal jQuery.event.trigger path. This may have negative effects for non-DOM usages however, so it's a question of what breaks when we fix this. See also #12379.
comment:29 Changed 8 months ago by gibson042
+1, let's give it our best shot.
comment:30 Changed 7 months ago by dmethvin
- Status changed from closed to reopened
- Resolution wontfix deleted
comment:31 Changed 7 months ago by dmethvin
- Owner set to dmethvin
- Status changed from reopened to assigned
comment:32 Changed 6 months ago by Dave Methvin
- Status changed from assigned to closed
- Resolution set to fixed
Fix #3827. Get the correct checkbox status for a click handler.
Changeset: 1fb2f92c357b985a5ba18d0938edd27b5f64d8c3
comment:33 Changed 4 months ago by dmethvin
#13194 is a duplicate of this ticket.
comment:34 Changed 4 months ago by Dave
Upgrading from 1.8.3 to 1.9.0 appears to have introduced an issue with checkboxes, and as this is the only related changeset, I assume this is the cause. It may be a lack of understanding of the original issue on my part, but I think my test case is solid enough.
Issue is that when using jQuery to set checkboxes to checked, the change is only visible* on the first occasion. jQuery can be used to uncheck the checkbox, but attempts to subsequently check the box again using jQuery do not work.
I have created a reduced test case here:
Repro steps:
- Click the tick button. The checkbox will be ticked.
- Click the untick button. The checkbox will be unticked.
- Click the tick button. The checkbox will not be visibly ticked.
However, if you use the Chrome Developer tools, you can see that the 3rd step has correctly added the "checked='checked'" attribute and value to the input. The issue appears to be a display issue.
Can be recreated in IE9 (9.0.8112.16421), Chrome (24.0.1312.52 m), Firefox (16.0.1), Safari (5.1.7 [7534.57.2]), Opera (11.60 1185) and Chrome Canary (26.0.1385.2 canary).
Works as expected in jQuery 1.8.3 (box is checked each time you click the tick button). Does not work in 1.9.0.
comment:35 Changed 4 months ago by dmethvin
@Dave this is specifically addressed in the upgrade guide. If you want to change or check the dynamic, changing, current state of the checkbox you should be using .prop() and not .attr(). http://jquery.com/upgrade-guide/1.9/#attr-versus-prop-
It's unrelated to this ticket.
Please follow the bug reporting guidlines and use jsFiddle when providing test cases and demonstrations instead of pasting the code in the ticket.
