1

I've recently discovered a very fundamental difference between the 2 methods of setting custom DOM attributes in Javascript. The difference is in how the HTML5 Selectors API interacts with those attributes (ie, in document.querySelector() and friends).

<button id="b3">View</button>

<script>
document.getElementById('b3').shape = 'square';
console.log( document.querySelector('*[shape]') ); // FAIL: returns null

document.getElementById('b3').setAttribute('shape','square');
console.log( document.querySelector('*[shape]') ); // WORKS: returns element
</script>

So basically if you apply attributes to an element without using .setAttribute() then you cannot later select the element by the attribute name.

BTW. This behaviour is consistent across browsers which makes me think it might be addressed by the standard, however I can't see it:

The selectors API standard doesn't appear to care:

Selectors allow the representation of an element's attributes. When a selector is used as an expression to match against an element, attribute selectors must be considered to match an element if that element has an attribute that matches the attribute represented by the attribute selector.

The entire attribute matching rule seems to boil down to "if the element has an attribute" and you would think that someElement.someAttribute = something would meet the criteria of "having an attribute" but for whatever reason it doesn't.

My question is basically why the difference? Is it actually part of a standard or just an identical implementation quirk in all the major browsers (IE11, FF38 and Chrome 43)?

SpliFF
  • 38,186
  • 16
  • 91
  • 120

1 Answers1

2

The reason is very simple - getElementById and all of those kind return an Element Object (see specs: http://www.w3schools.com/jsref/met_document_getelementbyid.asp)

Which means you set property shape on an object. Then you try to do a query selector, but you haven't modified the html that's queried. They are different things.

Andrey Popov
  • 7,362
  • 4
  • 38
  • 58
  • Are you saying that unless element[keyname] is declared in DTD it's not treated as a DOM attribute by default or just that everything is a property on an Element reference (what is 'id' then) ? – SpliFF Jun 02 '15 at 14:09
  • Quick answer is, .setAttribute() sets the DOM attribute while .shape = sets the shape property of the object. – Blake A. Nichols Jun 02 '15 at 14:10
  • Quick answer seems incomplete. If I do `element.id = 'something'` surely I'm setting an attribute, not a property right? Does setAttribute() modify the DTD or something? – SpliFF Jun 02 '15 at 14:11
  • Setting properties is actually changing value on the DOM. Querying is searching in the HTML. If you want to change the HTML, you should use `setAttribute`, so you can later on do a query based on changed attribute. If you simply want to set property, then you should not use query selector. `id` property is on both places. Think of this as parsing JSON file. You got the initial value, as well as parsed Objects. Setting attribute changes JSON, setting property changes Objects. – Andrey Popov Jun 02 '15 at 14:14
  • I doubt very much querying is "searching the HTML", the DOM is a live object built from the HTML. It should be the target of queries, not the HTML "source code". – SpliFF Jun 02 '15 at 14:17
  • `id` is, among some others, a unique property, directly mapped to the same-named attribute of HTMLElement. `shape` is not. Check these two tables - [attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes) and [properties](https://developer.mozilla.org/en-US/docs/Web/API/element#Properties). – raina77ow Jun 02 '15 at 14:19
  • Yes but what makes it a "unique property", surely the DTD does that by defining `id` in ATTLIST. Therefore setAttribute MUST be modifying the DTD (at least locally) right? – SpliFF Jun 02 '15 at 14:21
  • Yes, there are some properties that work in both directions. See this: http://jsfiddle.net/0psqyycz/ – Andrey Popov Jun 02 '15 at 14:23