Introductory discussions on good web user interface development drive home the importance of separating content (HTML), presentation (CSS), and behavior (JavaScript). The most powerful, and usually the slowest, way to interact programmatically with an HTML document on a web browser is to use the Document Object Model (DOM) API.
The principal references for DOM are the W3C standards, but the road to cross browser compatibility is fraught with pitfalls. Consider a document element. Elements can have attributes, which are expressed syntactically in the tags like this like so
<element_name attribute_name="attribute_value"> In the DOM, elements are represented using DOMNode objects, and they are distinguished from other varieties of nodes by the nodeType property, which is set to the constant ELEMENT_NODE (defined to be 1). One can access, modify, and remove node attributes by calling setAttribute(), getAttribute(), and removeAttribute() respectively.
The collection of all attributes associated with an element is available via the node's attributes property. It is exposed as a NamedNodeMap object, which allows the manipulation of attributes by name (the *NamedItem() methods) or by index (item()).
Given this information, the API sounds fairly straightforward. You can deal with attributes individually by name or as a set that you can iterate over. However, this isn't the only way that attributes can be modified under Internet Explorer.
In IE, an element's attributes are also exposed as properties on the object corresponding to the element node. Save for a few exceptions, like className for class, the property names line up with the attribute names.
What may be surprising is that the converse is true. If you add a property to an HTML element object, Internet Explorer will count that property among the list of attributes, regardless of whether the property corresponds to a valid HTML attribute. To verify this is the case, try this out... In an HTML element, create an element with an ID attribute for reference via the DOM.
<div id="target_element">
This text is contained by the DIV with id = "target_element".
</div>
Now, within a JavaScript function, use the DOM to get the node corresponding to this element and set a property on the element that does not correspond to a real HTML attribute:
var target_element =
document.getElementById("target_element");
target_element.fake_attribute = "foo";
Then iterate over the attributes NamedNodeMap for the element, checking to see whether such an attribute exists. In the code below, we check for an attribute name match and then generates an alert dialog informing the user whether that attribute's specified property is set to true or false.
var attributes_node_map = target_element.attributes;
for (var i = 0; i < attributes_node_map.length; ++i) {
if (attributes_node_map.item(i).name == "fake_attribute") {
alert("Is attribute fake_attribute specified? " +
attributes_node_map.item(i).specified
)
};
}
On Firefox, no dialog will be produced because the bogus property does not count as an attribute on the element. With Internet Explorer, the dialog will show up.
This difference came into play for us recently as we were debugging a piece of third-party JavaScript code. The source poked properties in HTML element objects for internal tracing purposes. The properties did not correspond to valid attributes, but IE would report them as such via the attributes property. Another portion of the code, which based its decision on whether there were no attributes set, would malfunction on IE because the attribute counts would be non zero.
Some additional notes on the dysfunctionality of attribute manipulation can be found at the QuirksMode website.