16

I gather from this post that almost always one wants to be accessing the DOM property, not the HTML attribute.

So what are the rare useful exceptions? In what situation is accessing the HTML attribute better than accessing the DOM property?

Community
  • 1
  • 1
Randomblue
  • 112,777
  • 145
  • 353
  • 547

3 Answers3

13

Sometimes the attribute doesn't map to changes in the property.

One example is the checked attribute/property of a checkbox.

DEMO: http://jsfiddle.net/mxzL2/

<input type="checkbox" checked="checked"> change me

document.getElementsByTagName('input')[0].onchange = function() {

    alert('attribute: ' + this.getAttribute('checked') + '\n' +
          'property: ' + this.checked);
};

...whereas an ID attribute/property will stay in sync:

DEMO: http://jsfiddle.net/mxzL2/1/

<input type="checkbox" checked="checked" id="the_checkbox"> change me

var i = 0;

document.getElementsByTagName('input')[0].onchange = function() {

    this.id += ++i;
    alert('attribute: ' + this.getAttribute('id') + '\n' +
          'property: ' + this.id);
};

And custom properties generally don't map at all. In those cases, you'll need to get the attribute.


Perhaps a potentially more useful case would be a text input.

<input type="text" value="original">

...where the attribute doesn't change with changes from the DOM or the user.


As noted by @Matt McDonald, there are DOM properties that will give you the initial value that would reflect the original attribute value.

HTMLInputElement.defaultChecked
HTMLInputElement.defaultValue
Community
  • 1
  • 1
user113716
  • 318,772
  • 63
  • 451
  • 440
  • 1
    Ok. But why is this useful? It seems the property is the important thing here. – Randomblue Sep 28 '11 at 20:11
  • @Randomblue: Only if you need to get the original value. I don't think it would be a common case. – user113716 Sep 28 '11 at 20:13
  • You may want to mention that attributes are essentially an "initial" state. A blurb about `HTMLInputElement.defaultChecked` (and how it is essentially the attribute value) would be icing on the cake :). –  Sep 28 '11 at 20:25
  • @MattMcDonald: Good idea. I'll update. Although by "initial state", I assume you're not necessarily implying that it is persistent. – user113716 Sep 28 '11 at 20:36
  • 1
    It's a default state rather than an initial state (I've been making this mistake too). If you change the `value` attribute, say, and then reset the form, the value will of the input will revert to the new attribute value. http://jsfiddle.net/CmRUU/ – Tim Down Nov 07 '11 at 12:40
  • It is **incorrect** and misleading to state "custom properties generally don't map at all. In those cases, you'll need to get the attribute". In fact, if you can augment a host object with a property in the first place, then that property will generally be readable using the standard property accessor syntax. And if you can add an attribute to an element via the element object representing it, then you can get its value with getAttribute(…). But it is **unwise** to do any of this; with host objects, all bets are off. Use native wrapper objects instead. – PointedEars Nov 12 '11 at 22:53
  • Well, most of jQuery is dependant on being able to set and get custom properties in host objects. What this means that it's a reliable practice at least in all the browsers that jQuery supports. http://jsfiddle.net/y5EXw/ – Esailija Nov 13 '11 at 15:46
  • @Esailija No, what this means is that nobody who uses jQuery knows about this, and nobody who could know bothered to check. jQuery is cargo cult programming, so this is not surprising. It took them v1.7 to realize that attr() can't be the answer (the rest of the world knew that by the turn of the century), and now they are winding around their mistakes with prop(). – PointedEars Nov 13 '11 at 20:21
  • @PointedEars my point was that using host object custom properties is very safe in all browsers that you'd care to develop for. As in, a response to `And custom properties generally don't map at all. In those cases, you'll need to get the attribute.` – Esailija Nov 13 '11 at 20:26
  • @Esailija There's the crux. You just don't develop for specific browsers. And you just don't change your compatibility tables when it suits your laziness. It's the Web, and *everyone* has the right to use it. – PointedEars Nov 13 '11 at 20:31
  • @PointedEars, By `browsers one would care to develop for` I didn't mean a specific browser but 99.999% of the market. There seems to be a misunderstanding, care to chat about it in the chat? – Esailija Nov 13 '11 at 20:50
  • I don't buy the market share logic. See "graceful degradation". If you have some new, convincing arguments, you know where to find me. – PointedEars Nov 13 '11 at 20:53
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4955/discussion-between-pointedears-and-esailija) – PointedEars Nov 13 '11 at 20:53
6

A rare exception is the case of attributes of a <form> element that could clash with elements in the form. For example, consider the following HTML:

<form id="theForm" method="post" action="save.php">
    <input name="action" value="edit">
</form>

The problem is that any input within a form creates a property corresponding to the input's name in the form element, overriding any existing value for that property. So in this case, the action property of the form element is a reference to the <input> element with name action. If that input did not exist, the action property would instead refer to the action attribute and contain the string "save.php". Therefore for properties of form elements corresponding to attributes, such as action and method, it's safest to use getAttribute().

var form = document.getElementById("theForm");

// Alerts HTMLInputElement in most browsers
alert( form.action );

// Alerts "save.php"
alert( form.getAttribute("action") );

// Alerts "post" because no input with name "method" exists
alert( form.method ); 

This is unfortunate; it would have been better if this mapping did not exist, since the elements property of the form already contains all the form elements keyed by name. I think we have Netscape to thank for this one.

Live demo: http://jsfiddle.net/z6r2x/

Other occasions to use attributes:

  • When accessing custom attributes, such as <div mymadeupattr="cheese"></div>
  • When serializing the DOM and you want values from the original HTML for input attributes such as value and checked.
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • +1 "This answer is useful (click again to undo)" Thanks, that was informative. – Stephen P Sep 29 '11 at 01:00
  • 1
    This mapping is one of the errors in JavaScript 1.1 (Netscape 3.0) that Netscape made in order to speed up adoption of JavaScript: the language should be simple to use. Competition and backwards compatibility then demanded to have the same mapping in MSHTML and later DOM implementations. So the rules of thumb here are: 1. Do not name controls the same as form object properties; never have the name "action" or "submit", for example. 2. Do not invent new attributes for elements (unless it is XHTML and you know what you are doing). 3. Never ever augment host objects, such as element objects. – PointedEars Nov 12 '11 at 23:03
  • @PointedEars: Full ACK, as you might say. Good to see you on Stack Overflow. Please be gentle :) – Tim Down Nov 12 '11 at 23:49
4

I can only come up with 2 more situations where accessing/setting attribute would have benefits over property.

Style attribute:

In a case where you are not allowed to use any framework, you can use style attribute to set multiple styles at once like so:

elem.setAttribute( "style", "width:100px;height:100px;" );

instead of doing this:

elem.style.width = "100px";
elem.style.height = "100px";

or this:

var styles = {width: "100px", height: "100px"}, style;

for( style in styles ) {
elem.style[style] = styles[style];
}

Be aware that setting style attribute overwrites the previous one. And its probably better to write a multiple style setter function anyway.

Href attribute:

A href attribute will usually contain a value like "/products", however the property will contain the resolved url, as in: "http://www.domain.com/products" instead of what you really want: "/products". So if you wanna do something dynamically with links, then reading the href attribute instead of property is better because it has the value you intended it to be.

Update

I suddenly found 2 more uses and I am sure there are more like this.

If you want to see if an element has custom tab index set, the easy way is to see if the element has the attribute. Since the default value for .tabIndex-property depends on element and cannot be easily used to see if the element has custom tabIndex.

Seeing if element has a custom .maxLength property. This cannot be seen from property either:

document.createElement("input").maxLength
//524288

It is impossible to tell if the value 524288 was there intentionally without dealing with the attribute.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • `elem.setAttribute("style", "width:100px;height:100px;")` will not work in older versions of IE or newer ones in compatibility modes, so I would avoid that for the general web. – Tim Down Nov 16 '11 at 12:21