Insights and discoveries
from deep in the weeds
Outsharked

Thursday, May 26, 2011

jQuery "has attribute" selector bug revisited: 1.6.1

In my last post I commented on problems with the jQuery "has attribute" selector in older browsers, specifically IE6 & 7 (and maybe a very old Firefox).

In 1.6.1 the functionality of attr has been returned to normal, which is good. The "has attribute" selector, unfortunately, is still broken. Run this fiddle in IE6 or 7. (Yeah I know jsFiddle barely works in IE6 and 7, but if you ignore the js errors you can still see the results).

Example 1: "nohref" attribute in "map" tag

The one that's being found is actually the invalid one ("nohref" is a property, and shouldn't have a value). Here's the fiddle showing this:

Example 2: "nohref" - both valid this time

Interestingly, it works sometimes. With "checked", the attribute is properly found either way:

Example 3: "checked" -- works!

With "custom" properties it never works, like with "nohref". So anyway, I'm still using the double-selector to properly check for 'has attribute' to be sure:

$('[someattribute][someattribute=""]')

Monday, May 9, 2011

jQuery "has attribute" selector bug and workaround

As of the current version of jQuery (1.6.0) the "has attribute" selector:

$('[someattribute]')

does not work properly in older browsers. I was running unit tests for some javascript in IE6 and found a very basic test failing, eventually determining that it was because of this bug. I was able to figure out the source of the bug and filed a bug report here.

Turns out this is not a new bug. Its actually been around since at least version 1.4.4 when the bug report that mine was dup'd to was filed: Bug 7770

I use this selector extensively to test for things like the existence of custom attributes, which identify certain behavior, or to identify elements matching a state of some kind.

I am not sure why it's taken so long for this fairly simple bug to be fixed, but until it is (and perhaps even after it is, unless you can be sure your code will never be used with older versions of jQuery) use the following workaround:

$('[someattribute][someattribute=""]')

The bug happens when Sizzle, jQuery's selection engine, is used to perform this selection, versus document.querySelectorAll, a native function that older browsers do not support. Well, let's be a little more specific. A native function that Internet Explorer 6.0 and 7.0, and Firefox 3.0 do not support. Unfortunately, those web browsers continue to be in widespread use. IE6 and 7 combined make up more than 10% of the global browser share. (Firefox 3.0 is under 1% now). In some areas these are much higher, e.g. like China, where, unfortunately, one of the target audiences of a web site I maintain resides.

Sizzle doesn't match an empty-string attribute value when using the "has attribute" selector. Using the "attribute value equals" selector gets around this. I'd use both selectors, though, because there are other inconsistencies in jQuery when testing value-less attributes. Furthermore, this behavior was changed in the current 1.6.0 release, and even further, it's going to be changed back in the next release, said one of the developers in a conversation about this over my bug report. See the jQuery blog for the 1.6.0 release for some discussion about this issue.

The upshot is that I don't think one should depend on the [attributename=""] to consistently select a valueless attribute, either, and if you need to test just for the existence of an attribute that could have a value or just be a flag, you'll definitely need to use both to account for either case.