Skip to main content

Bug Tracker

Side navigation

#4283 closed bug (fixed)

Opened March 02, 2009 06:09PM UTC

Closed April 15, 2011 02:30AM UTC

Last modified March 09, 2012 01:11AM UTC

.attr('checked') & XHTML 1.1 Strict

Reported by: andrew_ Owned by: timmywil
Priority: major Milestone: 1.6
Component: attributes Version: 1.5.2
Keywords: attr checked xhtml firefox Cc:
Blocked by: Blocking:
Description

When dealing with XHTML 1.1 Strict, Firefox 3.0.6 and a content type of application/xhtml+xml, the attr() method working with 'checked' does not function as previous versions of jQuery have. The following calls/parameters do not function as expected;

.attr('checked', false);

.attr('checked', '');

.removeAttr('checked');

The following html can be saved as an .xhtml file an opened locally within firefox, or placed on a server which is configured to send the content-type for xhtml correctly.

<!DOCTYPE html PUBLIC "-W3CDTD XHTML 1.1EN" "http:www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

<script type="text/javascript">

$(document).ready(function(){

$('#_Check').click(function(){

$(this).attr('checked', false); does not work

$(this).attr('checked', ''); does not work

$(this).removeAttr('checked'); does not work

this.checked = false; works

});

});

</script>

</head>

<body>

<input type="checkbox" id="_Check" /><label for="_Check">Click Me</label>

</body>

</html>

Attachments (1)
Change History (21)

Changed March 02, 2009 06:35PM UTC by andrew_ comment:1

For what it's worth, I have also been able to reproduce the incorrect behavior for the 'selected' attribute on <option> elements within <selects>s.

Changed March 03, 2009 02:55PM UTC by john comment:2

component: unfilledcore
resolution: → wontfix
status: newclosed

This is the correct behavior. If you're serving up your document as XML you need to treat it like a proper XML document - which means only modifying the actual DOM attributes (and not the expandos).

See here for more information:

http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_check.2Funcheck_an_input.3F

Changed March 03, 2009 03:14PM UTC by andrew_ comment:3

resolution: wontfix
status: closedreopened

You would be serving the document as xhtml+xml. Not pure xml. The xhtml spec clearly defines hundreds of attributes which are valid for tags. Prior to 1.3.2, this functioned as expected.

Additionally, the link you provided is negated by the test case provided when the ticket was opened. removeAttr() does not uncheck a checkbox in this case.

I dont feel that this was given enough consideration. (And suspect the test case wasnt even examined) We're not setting the checked property with an expando here, the browser is doing it via the click event, as it's default behavior mandates. Once the user has interacted with the checkbox and effectively 'checked' it, the provided attr() and removeAttr() methods do not have an effect on 'unchecking' the checkbox.

Changed March 03, 2009 05:17PM UTC by andrew_ comment:4

Additionally I have tested the same test case xhtml document as was attached in the following browsers;

Firefox 3.0.6 - Fails

Opera 9.64 - Passes

Chrome 1.0.154.48 - Fails

Safari 4 Public Beta (528.16) - Fails

IE 7 - Passes (but fails to recognize XHTML, so is moot)

I have done more investigation into this using tools such as Firebug. What I am finding is that the call to removeAttribute at line 1222 would appear to succeed, as my debugging tools are no longer reporting/showing the 'checked' attribute within the DOM inspector. However, the checkbox is not being 'unchecked'. It is only when the expando ".checked = false" is explicitly being set that the checkbox will be unchecked.

I have also run across this page which seems to be linked to a JQuery FAQ; http://www.nabble.com/Bug-in-FAQs-for-checkboxes-td21648503s27240.html

Although the example provided here is using jQuery 1.3, the result is the same. Changing the script tag to use 1.3.2 yields the same result;

Manually check the 'I'll be checked/unchecked' checkbox (via a mouse click on the checkbox), and then click the 'Uncheck - good' button. That button uses the removeAttr method and fails to uncheck the checkbox for the browsers listed above as 'Failed'. (I have attached faqtest.xhtml as a separate test case). As a point of reference, this example uses the XHTML 1.0 Strict spec, and not 1.1 as the previous example had, leaning towards this as a general XHTML issue.

For this situation, would it not be valid to examine the object at hand to see if an expando method exists, and attempt to intelligently degrade to use that expando via attr()?

Changed March 03, 2009 05:38PM UTC by andrew_ comment:5

Please excuse the multiple posting, as there seems to be no way to edit.

Upon further investigation I found the following;

1219 removeAttr: function( name ) {

1220 jQuery.attr( this, name, "" ); 'checked' attribute does not exist in attributes collection

1221 if (this.nodeType == 1) 'checked' attribute created by previous call and added to the attributes collection

1222 this.removeAttribute( name );

1223 }, //'checked' attribute removed by removeAttribute

This execution path would seem to confirm that the actual checked state of the checkbox is not effected by removeAttr.

Changed March 03, 2009 10:36PM UTC by dmethvin comment:6

Andrew, I spent about 45 miniutes looking at your test case and thinking about the implications last night, then posted to the jQuery Dev list. So it's definitely gotten some consideration.

jQuery is doing exactly what you asked and no more, setting and getting *attributes*. If you use the browser's

setAttribute
and
removeAttribute
methods they exhibit the exact same behavior. I know, because I experimented with your test case.

For this situation, would it not be valid to examine the object at hand to see if an expando method exists, and attempt to intelligently degrade to use that expando via attr()?

jQuery does many hacky things in the name of compatibility for HTML documents. It seems that one goal of XHTML+XML is to require a high level of precision on the part of the designer/developer to say precisely what they mean with no sloppiness. There are significant gotchas to trying to read minds.

Just before your ticket last night, I looked at #4281 which is the other side of this coin. That person wants to know why

.attr("onclick", "javascriptcode")
only works once; it's due to the browser-induced magic of attributes becoming properties. The same goes for an element's style property (a CSSStyleDeclaration object) versus its style attribute (a string, if it's specified at all).

It seems like this case would benefit from a

$().prop()
method that you could use that when you know for sure that you need to get/set a property and not an attribute. If you want the old fuzzy do-what-I-mean behavior subject to all the caveats, just serve the document as HTML. IE is going to do that anyway, so I am not sure of the benefits of using XHTML+XML at this point.

Changed March 03, 2009 11:11PM UTC by andrew_ comment:7

>jQuery is doing exactly what you asked and no more, setting and getting *attributes*. If you use the browser's setAttribute and removeAttribute methods they exhibit the exact same behavior. I know, because I experimented with your test case.

Confirmed, and I agree. I hope that my posts have been interpreted more as an 'unexpected behavior' more than a 'fault of jquery'.

>It seems like this case would benefit from a $().prop() method that you could use that when you know for sure that you need to get/set a property and not an attribute.

This would be fantastic.

>IE is going to do that anyway, so I am not sure of the benefits of using XHTML+XML at this point.

(This is quite the tangent, but it offers explanation) I took over a development lead for the UI of an application my company is developing with a team overseas. The team overseas has very little understanding about why good html structure is important and how the browser(s) interprets the html that [they] are given. The html in this project was nothing short of tag soup, and had so many errors it was mind blowing. We decided to move ahead with XHTML in order to enforce runtime validation (thank you Firefox) so any mistakes that were made were quite obvious, allowed us to fix the previous mistakes quite easily given the dynamic nature of the site and also put into place an accountability measure. On the whole it was a good move for us. If it were not for those reasons, we would still be serving HTML 4.0.

Thanks for the time you've given to this issue and for examining the test cases I attached. Your consideration of the issue is much appreciated.

Changed March 26, 2009 02:51PM UTC by andrew_ comment:8

@ dmethvin

Just following up to see if there has been any progress with this.

Changed March 26, 2009 03:53PM UTC by andrew_ comment:9

I've uploaded a temporary fix by proxying attr and remoteAttr. It's not an ideal solution or fix. But for folks with the server sending application-xhtml+xml content type correctly, this will work.

Changed April 25, 2009 04:56PM UTC by alex_sh comment:10

I'm affected by the same problem.

The thing is, setAttribute() / removeAttribute() (and, by extension, jquery's attr()) don't guarantee that the attribute value will actually change the widget state.

For that, properties must be used. However, this is highly impractical because there seems to be no way to mass-apply the property values on jquery-selected elements.

Also, note that the types are different. For example, to disable the input element, the "disabled" attribute value must be set to "disabled" (works for both html and xhtml), while the property is boolean, and must be set to true.

$().prop() (or something like that) would be highly welcome. Something like $(":input").prop("disabled", true).

This affects properties like disabled, checked, selected, readOnly (the attribute is named readonly), etc...

This change would allow people to use the same scripts for xhtml and html, thus allowing them to serve them to non-xhtml-compliant user agents.

Changed July 23, 2009 12:11PM UTC by James Tindall comment:11

This really needs fixing. $(':input').attr('checked', 'checked') does not add the attribute at all. How can this not working be expected behaviour?

Changed December 01, 2009 11:00PM UTC by yehuda comment:12

milestone: 1.41.5

Changed October 19, 2010 06:48AM UTC by snover comment:13

milestone: 1.4.41.5
status: reopenedopen

Changed October 20, 2010 05:05PM UTC by dmethvin comment:14

#7257 is a duplicate of this ticket.

Changed March 26, 2011 12:31PM UTC by tomgrohl comment:15

_comment0: I don't know if this has already been fixed for jQuery 1.6, but I've found a way to fix this using attrHooks. \ \ I've wrote a attrHook for the checked attribute, which will set the checked if true or "checked" was passed, and then removing the attribute if false or "" was passed, intead of just changing the attributes value. \ \ Something like: \ \ {{{ \ //For setting as checked \ $(elem).attr("checked", true); \ $(elem).attr("checked", "checked"); \ \ //For setting as un-checked \ $(elem).attr("checked", false); \ $(elem).attr("checked", ""); \ }}} \ \ I did find something that might affect the attrHook working in xhtml documents. \ \ I had the same html page. One saved as index.html and the other as index.xhtml. \ \ Calling document.documentElement.nodeName on the first one returns "HTML" as html nodes are uppercase. \ \ Calling it on index.xhtml, as it is classed as an xml document, returns "html", obvously due to xml node names being case sensitive. \ \ This is used in Sizzle.isXML and is only checking for "HTML" (unless there is a reason for this). \ \ Because of this, some jQuery methods are affected when they shouldn't be, so attrHooks might not get called if document.documentElement.nodeName returns "html" \ \ I changed Sizzle.isXML to ( adding toUpperCase to the nodeName ): \ {{{ \ Sizzle.isXML = function( elem ) { \ // documentElement is verified for cases where it doesn't yet exist \ // (such as loading iframes in IE - #4833) \ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; \ \ return documentElement ? documentElement.nodeName.toUpperCase() !== "HTML" : false; \ }; \ }}} \ \ If this check affects removing a checked attribute in an xhtml document, it must affect others. \ \ I've done some tests ( Couldn't add them into jsFiddle as it doesn't have 1.6 ) \ \ Which can be found here: http://bit.ly/fG44bd \ \ 1301142787039411

I don't know if this has already been fixed for jQuery 1.6, but I've found a way to fix this using attrHooks.

I've wrote a attrHook for the checked attribute, which will set the checked if true or "checked" was passed, and then removing the attribute if false or "" was passed, intead of just changing the attributes value.

Something like:

//For setting as checked
$(elem).attr("checked", true);
$(elem).attr("checked", "checked");

//For setting as un-checked
$(elem).attr("checked", false);
$(elem).attr("checked", "");

I did find something that might affect the attrHook working in xhtml documents.

I had the same html page. One saved as index.html and the other as index.xhtml.

Calling document.documentElement.nodeName on the first one returns "HTML" as html nodes are uppercase.

Calling it on index.xhtml, as it is classed as an xml document, returns "html", obvously due to xml node names being case sensitive.

This is used in Sizzle.isXML and is only checking for "HTML" (unless there is a reason for this). I think this is the reason why this bug occurs.

Because of this, some jQuery methods are affected when they shouldn't be, so attrHooks might not get called if document.documentElement.nodeName returns "html"

I changed Sizzle.isXML to ( adding toUpperCase to the nodeName ):

Sizzle.isXML = function( elem ) {
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833) 
	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;

	return documentElement ? documentElement.nodeName.toUpperCase() !== "HTML" : false;
};

If this check affects removing a checked attribute in an xhtml document, it must affect others.

I've done some tests ( Couldn't add them into jsFiddle as it doesn't have 1.6 )

Which can be found here: http://bit.ly/fG44bd

Changed March 26, 2011 12:56PM UTC by timmywil comment:16

Yes, this has been done in attrhooks for 1.6. All falsy values will remove Boolean attributes such as checked. I haven't looked into the XHTML issue, but I'll do some testing.

Changed March 26, 2011 02:37PM UTC by tomgrohl comment:17

@timmywil

Haha. Thought it might have been. Nice one!

Changed April 01, 2011 02:13AM UTC by dmethvin comment:18

component: coreattributes
milestone: → 1.6

$().prop() will land with the attr rewrite.

Changed April 01, 2011 02:21AM UTC by timmywil comment:19

owner: → timmywil
status: openassigned

Changed April 15, 2011 02:30AM UTC by timmywil comment:20

resolution: → fixed
status: assignedclosed
version: 1.3.21.5.2

Changed April 15, 2011 05:43PM UTC by timmywil comment:21

This has been changed. Not all falsy values will remove the common Boolean attributes, just false.