I ask this question based on the following link: https://developer.mozilla.org/en-US/docs/Web/API/Attr
I see so many developers use these methods and honestly I am not entirely sure if they are really deprecated as a whole or just in a certain context. Either way, it does list them as deprecated, which is why im asking: what valid and up-to-date alternatives are there? Specifically for:
removeChild, textContent, appendChild. Even insertBefore is deprecated.
My guess is that you are confusing node objects and attribute objects. The functions you named are commonly used with the former, but not the latter. The MDN article is only describing attribute objects.
For more information:
A <div> is a node, and it could have an attribute data-foo="bar" on it.
It is common to append children or modify text to a node. For example, given:
var node = document.createElement('div');
node.innerHTML = '<p>Hello</p><p> World</p>';
node.removeChild(node.firstChild);
would produce HTML of <div><p> World</p></div>
However, this doesn't really make sense for attributes. Attributes are essentially just strings attached to a node. The common actions that are used with attributes are name and value. For example:
var node = document.createElement('div');
node.setAttribute('data-foo', 'bar');
var attr = node.getAttributeNode('data-foo');
console.log(attr.name); // prints 'data-foo'
console.log(attr.value); // prints 'bar'
console.log(typeof attr); // prints 'object'
At least personally, I have rarely had use for the Attr object, instead node.getAttribute('data-foo') returns a string of bar, and that is sufficient for my needs.
As to why those methods exist in the first place on attr objects, I will simply copy/paste from the MDN article you linked:
Warning: In DOM Core 1, 2 and 3, Attr inherited from Node. This is no longer the case in DOM4. In order to bring the implementation of Attr up to specification, work is underway to change it to no longer inherit from Node. You should not be using any Node properties or methods on Attr objects.
Related
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:
http://www.w3.org/TR/css3-selectors/#attribute-selectors
http://www.w3.org/TR/selectors-api/
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)?
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.
This is related to the question javascript cloneNode and properties.
I'm seeing the same behaviour. Node.cloneNode does not copy over any properties that I add myself (code from original post):
var theSource = document.getElementById("someDiv")
theSource.dictator = "stalin";
var theClone = theSource.cloneNode(true);
alert(theClone.dictator);
theClone does not contain any property "dictator".
I haven't been able to find any explanation for why this is the case. The documentation on MDN states that cloneNode "copies all of its attributes and their values", a line which is taken directly from the DOM specification itself.
This seems broken to me as it makes it next to impossible to do a deep copy of a DOM tree that contains custom properties.
Am I missing something here?
A property is not equal to an attribute.
Use setAttribute() and getAttribute() instead.
var theSource = document.getElementById("someDiv")
theSource.setAttribute('dictator','stalin');
var theClone = theSource.cloneNode(true);
alert(theClone.getAttribute('dictator'));
Not every property corresponds to an attribute. Adding a custom property to an element does not add an attribute, so what happens when you do that is not covered by the DOM spec.
In fact, what happens when you add a property to a host object (such as a DOM node) is completely unspecified and is by no means guaranteed to work, so I'd strongly recommend against doing it. Instead, I'd suggest using wrappers if you want to extend the functionality of host objects (as jQuery and many other libraries do).
Tested this. cloneNode does include the custom attribute in the clone, but that attribute can't be retrieved directly. Try:
var theSource = document.getElementById("someDiv")
theSource.dictator = "stalin";
//or better / more cross browser compatible
theSource.setAttribute('dictator','stalin');
var theClone = theSource.cloneNode(true);
alert(theClone.getAttribute('dictator')); //so, use getAttribute
It may be a browser problem with cloning expando properties. I ran a testcase (see later) from this rather old bugzilla report. It didn't work in Chrome and Firefox (both latest versions).
//code from testcase # bugzilla
var a = document.createElement("div");
a.order = 50;
alert(a.order);
b = a.cloneNode(true);
alert(b.order);
I'm trying to get a list in JavaScript (not using jQuery) of all the elements on the page with a specific class name. I therefore employ the getElementsByClassName() function as follows:
var expand_buttons = document.getElementsByClassName('expand');
console.log(expand_buttons, expand_buttons.length, expand_buttons[0]);
Note that I have three anchor elements on my page with the class 'expand'. This console.log() outputs
[] 0 undefined
Next, for kicks, I threw expand_buttons into its own array as follows:
var newArray = new Array(expand_buttons);
console.log(newArray, newArray.length);
This suddenly outputs
[NodeList[3]] 1
and I can click through the nodelist and see the attributes of the three 'expand' anchor elements on the page. It's also worth noting that I was able to get my code working in a w3schools test page.
It may also be of note that my use of document.getElementsByName actually does output (to the console) an array of elements, but when I ask for its length, it tells me 0. Similarly, if I try to access an array element using array_name[0] as normal, it outputs 'undefined', despite there clearly being an element inside of an array when I print the object to the console.
Does anybody have any idea why this might be? I just want to loop through DOM elements, and I'm avoiding jQuery at the moment because I'm trying to practice coding with vanilla JavaScript.
Thanks,
ParagonRG
It's not so much a JavaScript thing as it is a web browser thing. That API is supplied by a native object (the document object), and by the DOM spec it returns a NodeList object. You can treat a NodeList like an array, and it's similar, but distinctly different (as you've noticed).
You can always copy a NodeList to a new array:
var nodeArr = Array.prototype.slice.call(theNodeList, 0);
or in modern ES2015 environments:
var nodeArr = Array.from(theNodeList);
JavaScript always exists in some runtime context, and the context can include all sorts of APIs that provide facilities to JavaScript code. A web browser is one of those contexts. The DOM is specified in a way that's not especially partial to JavaScript; it's a language-neutral interface definition.
I guess the short version of this answer would be, "because it just does."
It doesn't return an array because the object it returns is "live", specifically it is a live NodeList:
In most cases, the NodeList is a live collection. This means that changes on the DOM tree are going to be reflected on the collection.
"Warning: In DOM Core 1, 2 and 3, Attr inherited from Node. This is no longer the case in DOM4. In order to bring the implementation of Attr up to specification, work is underway to change it to no longer inherit from Node . You should not be using any Node properties or methods on Attr objects. Starting in Gecko 7.0 (Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4) , the ones that are going to be removed output warning messages to the console. You should revise your code accordingly. See Deprecated properties and methods for a complete list."
Scrolling down the page, we can see replacements for nodeName and NodeValue, using Attr.name and Attr.value.
https://developer.mozilla.org/en/DOM/Attr#Deprecated_properties_and_methods
What does it really mean for other methods like attributes or childNodes?
The reference says it is deprecated but they don't give any replacement!
It is deprecated for an Attribute but is it for a Node too?
Attr object: http://www.w3schools.com/jsref/dom_obj_attr.asp
Edit: nodeValue will ONLY be deprecated for Attributes (Attr) since Attr will not inherit from a Node anymore in DOM Level 4:
Here's a quick example that helped me to understand:
<div id="myAttribute">myTextNode</div>
var myDiv = document.getElementById("myAttribute");
// If you want to get "myAttribute" from div tag
alert(myDiv.attributes[0].value);
// Correct way to get value of an attribute (displays "myAttribute")
alert(myDiv.attributes[0].nodeValue);
// Working too but deprecated method for Attr since it doesn't inherit from Node in DOM4 (.nodeValue is specific to a Node, not an Attribute)
// If you want to get "myTextNode" from div tag
alert(myDiv.childNodes[0].value);
// Not working since .value is specific to an attribute, not a Node (displays "undefined")
alert(myDiv.childNodes[0].nodeValue);
// Working, .nodeValue is the correct way to get the value of a Node, it will not be deprecated for Nodes! (displays "myTextNode")
Maybe this will avoid confusion to others when accessing Attributes/Nodes :)
What they are saying is that objects that were Attr instances (e.g. such as those returned by Element.getAttributeNode()), used to have properties that it inherited from Node.
However, because this is not the case in DOM4, they are trying to remove this inheritance. Because of this, when you now get an instance of a Attr object, the properties listed in the deprecated list will behave as they're documented.
The big question: It is deprecated for an Attribute but is it for a Node too?: No, they are not deprecated. You can see the list of properties Node has from it's own documentation page.
Attr objects aren't used much (ever?) anyway; are you sure this concerns you?
It appears that sometimes object.setAttribute(attrib,value) isn't equivalent to object.attrib=value in javascript?
I've got the following code, which works fine:
var lastMonthBn = document.createElement('input');
lastMonthBn.value='<'; // This works fine
lastMonthBn.type='button'; // This works fine
But the following code doesn't:
var div = document.createElement('div');
div.class = 'datepickerdropdown'; // No luck here!
So i need to use the following:
div.setAttribute('class','datepickerdropdown');
My question is, why? From reading this, I thought that object.setAttribute(blah,value) was the same as object.blah=value??
Properties and Attributes aren't really the same, however the DOM exposes standard attributes through properties.
The problem you're facing specifically with the class attribute is that class is a future reserved word.
In some implementations the use of a future reserved word can cause a SyntaxError exception.
For that reason, the HTMLElement DOM interface provides a way to access the class attribute, through the className property:
var div = document.createElement('div');
div.className = 'datepickerdropdown';
Remember, attributes aren't the same as properties, for example:
Immagine a DOM element that looks like this:
<div></div>
If you add a custom attribute to it, e.g.:
myDiv.setAttribute('attr', 'test');
An attribute will be added to the element:
<div attr="test"></div>
Accessing attr as a property on the div element, will simply give you undefined (since is not a property).
myDiv.foo; // undefined
If you bind a property to an element, e.g.:
myDiv.prop = "test";
The getAttribute method will not be able to find it, (since is not an attribute):
myDiv.getAttribute('test'); // null
Note: IE wrongly messes up attributes and properties. :(
As I've said before, the DOM exposes standard attributes as properties, but there are some exceptions that you'll have to know:
The class attribute, is accessible through the className property (the problem you have).
The for attribute of LABEL elements, is accessible through the htmlFor property (collides with the for statement).
Attributes are case-insensitive, but the language bindings for JavaScript properties are not, so the convention is to use the names is camelCase to access attributes through properties, for example the ones formed by two words, e.g. cellSpacing, colSpan, rowSpan, tabIndex, maxLength, readOnly frameBorder, useMap.
It should be noted that browsers like Safari will NOT run JavaScript if keywords like "class" or "int" are present.
So it's a cross-browser support sort of thing. "class" is present in JS2.0 [I believe a package system is available there too]
...
I should also note that in IE, setAttribute [for non-class things, since setAttribute should be use-able for other members such as "style"] can be glitchy.