Retrieving HTML attribute values "the DOM 0 way"
Asked Answered
B

3

4

jQuery has an attr() method which retrieves the value of a given HTML attribute. For instance:

var foo = document.getElementById("foo");
$(foo).attr("id");

But, performance-wise this is not optimal since an jQuery object has to be created just to call the attr() method. This performs better: foo.id.

So, ideally we would want to avoid using attr(). But, can we do that (for any attribute)? I believe foo.id and foo.value is "safe" (cross-browser), but I remember having issues with foo.href.

Here is a list of various attributes that I would like to be able to retrieve "directly":

For any element: foo.id, foo.name
For anchors: foo.href, foo.target, foo.rel
For images, objects, iframes: foo.src, foo.width, foo.height
For form elements: foo.checked, foo.selected, foo.disabled, foo.readonly, foo.type, foo.value, foo.action

So the question is: Are the above expressions cross-browser? Can I use them safely?

A link to an article which examines this issue would also be nice.

Edit (based on the answers): The expressions in bold are not safe to use!

Brogdon answered 15/12, 2010 at 23:58 Comment(0)
A
4

Looking at how jQuery handles it:

  • href, src, and style attributes need special treatment.
  • Safari has a bug when accessing "selected" attribute on a select element. If accessing the "selected" attribute, Safari needs special treatment.

Check out the jQuery source, and search for this line to see what I mean by "special treatment":
attr: function( elem, name, value, pass ) {

In short: I think it safe to do what you want for most of the attributes listed, except for those shown above.


To keep things easy, you could do this:

$foo = $("#foo");
console.log( $foo.attr("id"), $foo.attr("style"), $foo.attr("href") );
Only 1 jQuery object is made, and you don't have to worry about manually handling anything.
Adjust answered 16/12, 2010 at 0:15 Comment(3)
OK, to sum up: href and src need attr(). Got it. (The style attribute is messed up so I wouldn't want to retrieve it anyway.)Variate
Caching jQuery objects (var $foo = $("#foo"); is a good practice on page-load. However, inside event handlers, we have the this value which points to the DOM element related to the event. In this case, creating $(this) is a performance penalty and being able to avoid it by retrieving attribute values "the DOM 0 way" is a nice technique.Variate
@ŠimeVidas you can do the same for objects inside event handlers too, unless they are dynamically changing. Just put them in an each loop and save $this once on DOM load. A bit subpar but could be helpful for performance. Another method to increase performance would be attaching the event to the parent and using the event's target, if there are enough elements (or enough number of event calls) that make you worried about performance. Of course, if what you are doing warrants so (e.g. building a widget or app that will be very heavily used), you can always handcraft everything in plain JS.Woodley
A
13

jQuery's attr() method is misleadingly named, badly documented and hides a very important distinction: the difference between attributes and properties, something which appears to be poorly understood by many web developers, particularly those whose introduction to JavaScript has come from jQuery.

If you read no further, just take this away: you will almost never need to use attributes. It's almost always better to use the corresponding property. Indeed, this is what jQuery's attr() method usually does used to do prior to version 1.6.

Reasons to use a property and avoid getAttribute() and setAttribute() when dealing with HTML DOMs:

  • IE's implementation is broken. In older versions and quirks modes of more recent versions, attributes map directly to properties, which is contrary to the DOM standard. One consequence of this is that event handler attributes (onclick etc.) are thoroughly broken in IE. Always use a property for an event handler. Another consequence of this is that IE in these modes and versions requires you to use getAttribute("className") instead of getAttribute("class") to retrieve the class attribute.
  • Properties are (mostly) consistently implemented cross-browser
  • The relationship between some properties and attributes is not as you might think. Some attributes, notably the value attribute of an <input> element, are not tied to the property with the same name: once the value of an input has been changed (either by the user or script), getting or setting the value attribute has no effect. Instead, the value attribute is synchronized with the defaultValue property.
  • Properties are usually more convenient. Think for example about boolean attributes such as checked: this is represented in the DOM as a boolean checked property while confusion reigns about how to set the checkedness of a checkbox using an attribute. Is it removeAttribute("checked")? setAttribute("checked", "")? setAttribute("checked", false)? All are wrong, because the checked attribute is actually mapped to the defaultChecked property.

There are some situations where using an attribute may be desirable. For example, the href property of an <a> element always reports a fully qualified URL while getAttribute("href") will return the string specified in the HTML href attribute verbatim. Except, of course, in IE. jQuery's attr() does attempt to normalize this kind of inconsistency.

Some more information on this subject: http://reference.sitepoint.com/javascript/Element/setAttribute, and also this from MSDN: http://msdn.microsoft.com/en-us/library/dd347148%28v=vs.85%29.aspx

Finally, I strongly recommend using the DOM properties directly wherever possible rather than using jQuery's attr() method, but there are special cases (such as href) it handles that you need to be aware of. Of the properties you mention, all of them are completely safe to use cross-browser, with the following exceptions:

  • foo.href and foo.src (which suffers from a similar problem) as mentioned above.
  • foo.type can only be set on an <input> element before it's been added to the DOM.
  • foo.selected (where foo is an <option> element) apparently has a bug in older versions of Safari, as noted in another answer.
Achromatous answered 16/12, 2010 at 1:55 Comment(13)
Yea, I know about that attribute/property difference. :) But I was afraid that people won't understand if I use the term "DOM HTML element property". The term "attribute" is incorrect but it's widely used and understood to refer to certain DOM element properties that were created based on the HTML attributes in the HTML source code.Variate
Also, I believe IE9 beta resolved the href issue. foo.href returns the full URL, whereas foo.attributes.href.value and foo.getAttribute("href") returns the value of the href attribute in the source code.Variate
@Šime Vidas: I like to take every opportunity to point out the difference between DOM attributes and properties. Sorry if it was unnecessary for you. I've now added a bit about the properties you asked about.Achromatous
@Tim Yea, I like to do that too occasionally, but it can be difficult. I remember having a lengthy discussion via comments in another SO question. I was trying to explain to another user that the members of the attributes object of an DOM element are not HTML attributes but in fact DOM Attr node properties (objects), and that HTML attributes only exist in the HTML source code, whereas properties exist in the DOM (and also that the term attribute has a different meaning in JavaScript: a property of an object has internal attributes). But he just couldn't get it, so I gave up.Variate
@Tim According to that MSDN article, Microsoft appears to use this terminology: 1. the original HTML attributes are referred to as content attributes (they can be accessed via the attributes property or the getAttribute() method, 2. the properties of the DOM element that were created based on those HTML attributes are referred to as DOM attributes.Variate
@Šime: Yes, I noticed that too on the MSDN article. I've never seen that terminology elsewhere though.Achromatous
@Tim What about the name attribute? I just realized that a DOM element node based on this source code: <div name="foo"></div>, does not contain a name property. Demo: jsfiddle.net/YjgCbVariate
@Šime: That's because name is not a valid attribute for <div> elements. For elements for which name is valid, there is a corresponding name property that works fine.Achromatous
According to John Resig's keynote at JSConf, jQuery 1.6 will feature a new method, prop(), which will help differentiate between properties and attributes.Yuzik
@yc: I'm not sure whether this is good news or not. It depends on whether they change the behaviour of attr(), which I don't really think they can do at this point. Given that attr() already uses properties, I'm not sure what a new prop() method could do that would help, short of deprecating attr() and replacing it with two separate methods. I think they made their bed 5 years ago with attr() and now they have to lie in it.Achromatous
@Tim Down I think they're planning on changing attr()s behavior, that's why its happening in a 1.6 release rather than a 1.5.3 or something like that. Link: ontwik.com/javascript/… 14:00 in: John Resig: "We think this will have the potential to break things in code, but we think its an essential change."Yuzik
@yc: Wow. That is going to break all kinds of stuff so I wouldn't be surprised if they backtracked on that, but I hope not. Resig's right, it is an essential change. Thanks for the link.Achromatous
"We think this will have the potential to break things..." New top nominee for understatement of the year.Fatality
A
4

Looking at how jQuery handles it:

  • href, src, and style attributes need special treatment.
  • Safari has a bug when accessing "selected" attribute on a select element. If accessing the "selected" attribute, Safari needs special treatment.

Check out the jQuery source, and search for this line to see what I mean by "special treatment":
attr: function( elem, name, value, pass ) {

In short: I think it safe to do what you want for most of the attributes listed, except for those shown above.


To keep things easy, you could do this:

$foo = $("#foo");
console.log( $foo.attr("id"), $foo.attr("style"), $foo.attr("href") );
Only 1 jQuery object is made, and you don't have to worry about manually handling anything.
Adjust answered 16/12, 2010 at 0:15 Comment(3)
OK, to sum up: href and src need attr(). Got it. (The style attribute is messed up so I wouldn't want to retrieve it anyway.)Variate
Caching jQuery objects (var $foo = $("#foo"); is a good practice on page-load. However, inside event handlers, we have the this value which points to the DOM element related to the event. In this case, creating $(this) is a performance penalty and being able to avoid it by retrieving attribute values "the DOM 0 way" is a nice technique.Variate
@ŠimeVidas you can do the same for objects inside event handlers too, unless they are dynamically changing. Just put them in an each loop and save $this once on DOM load. A bit subpar but could be helpful for performance. Another method to increase performance would be attaching the event to the parent and using the event's target, if there are enough elements (or enough number of event calls) that make you worried about performance. Of course, if what you are doing warrants so (e.g. building a widget or app that will be very heavily used), you can always handcraft everything in plain JS.Woodley
W
-1

1) I don't really think performance is an issue. My guess is that 'foo' is simply a pointer, not an object that takes up space in memory. Not sure about this though.

2) You don't have to create a variable foo at all. $("#foo").attr("id") will do.

3) DOM has several methods for accessing attributes. Try .getAttribute("name"), .setAttribute("name"), and .removeAttribute("name")

Wilberwilberforce answered 16/12, 2010 at 0:15 Comment(5)
1) this.id is more then 10x faster than $(this).attr("id") 3) I believe those methods don't work in IE6 and IE7Variate
getAttribute() should work fine in IE6 and IE7. The problem is that it's inconsistent across browsers.Adjust
IE6 should support all of these methods. They are part of DOM1.Wilberwilberforce
But there seems to be an issue: en.wikipedia.org/wiki/…Variate
@simshaun, @jeff: IE 6 and 7's implementation of attributes is totally broken. See my answer.Achromatous

© 2022 - 2024 — McMap. All rights reserved.