What is the parent when I create an element with document.createElement()? - javascript

If I create a element using document.createElement(), what is its parent? Is it body? Sorry for such a basic question but I've tried using JavaScript to find the parent and it returns an object, not really sure about this one.
Thanks

The element is created in memory and does not have any parent (yet).
When you place the element in the DOM using appendChild() or similar methods, it will have a parent.
JavaScript will return null if you try to access an element that doesn’t exist, and that includes parents to elements that only exist in memory.
To access the element, assign it to a variable, f.ex:
var elem = document.createElement('div'); // elem is now the element reference
You don’t need to explicitly delete elements that you haven’t appended to the DOM as they only exist in memory and will be wiped out once they are no longer referenced.

Until you attach it to something, it is nothing (null).
> x = document.createElement("div");
<div>​</div>​
> x.parentNode
null
> document.body.appendChild(x);
<div>​</div>​
> x.parentNode
<body></body>
With regards to your comment, given an array of elements [x, y, z], which may or not be inserted into the DOM, you can remove those in the DOM as follows;
var els = [x, y, z];
for (var i=0;i<els.length;i++) {
if (els[i].parentNode) {
els[i].parentNode.removeChild(els[i]);
}
}
... as only elements in the DOM will have a truthy parentNode.

Related

Iterate over all node objects not only element objects

I've read the following very good article:
Difference between Node object and Element object?
as to clear out the difference between a node object and an element object. I 've understood that
element objects are a subset of node objects.
So, after that I've come upon the following query: In which way may I iterate through all the node objects? By using document.getElementsByTagName('*') ,I think I am getting all the element objects since all of them have value 1 for their .nodeType property. Am I right and if yes, how may I include into my results all these nodes that are not elements?
Thank you
I don't believe there's any standard DOM function that will return every Node (as opposed to Element) in the entire document.
You would probably have to use recursive DOM traversal to find them all with something like this:
function getAllNodes(parent, nodes) {
parent = parent || document;
nodes = nodes || [];
var child = parent.firstChild;
while (child) {
nodes.push(child);
if (child.hasChildNodes) {
getAllNodes(child, nodes);
}
child = child.nextSibling;
}
return nodes;
}
As written you can just write var nodes = getAllNodes() and it'll automatically start at the document root.
The answer is in your question. You use document.getElementsByTagName. Let me repeat that for you. getElementsByTagName.
Non-element nodes don't have a tag name, an identifier, or anything like that. The only way to designate them is by where they are in the document structure.
You can get a reference to an Element and then browse its childNodes, as has been suggested already.
Another way is to use an XPath, which, unlike CSS selectors, is able to point directly to any Node, including text and comment Nodes.
document.evaluate("*", document.documentElement, null, XPathResult. UNORDERED_NODE_ITERATOR_TYPE)

Checking if an element created by javascript exists using only javascript [duplicate]

This question already has answers here:
How can I check if an element exists in the visible DOM?
(27 answers)
Closed 8 years ago.
The question is quite straightforward. Is there a javascript only (no jQuery/other library pls) method of checking if an element created via javascript exists?
For instance, if I did this:
var foo=document.createElement("div");
document.getElementById("bar").appendChild(foo);
Would there be a way to check if foo already exists?
You could simply get the element by id and see if its not null.
var foo=document.createElement("div");
document.getElementById("bar").appendChild(foo);
foo.setAttribute("id","foo");
var ele = document.getElementById("foo");
if(ele !== null){ alert("Hi");}
foo is not an element, it's a variable whose value is an element. There are different ways to interpret your question.
Is the value of the variable foo a DOM element?
If you want to check if the variable foo exists and has as its value an element, you can say
foo && typeof foo === 'object' && foo.nodeType
or something similar. This will check whether the element is any kind of Node. To check for an element, use foo.nodeType === Node.ELEMENT_NODE.
Is a particular HTML element in the DOM?
If you want to check if the element held in variable foo is in the DOM, as opposed to having been created, but not yet inserted, then:
foo.baseURI
since baseURI is set only upon DOM insertion. You might think you could check parentNode, which is also not set until DOM insertion, but children of the non-inserted element, if any, will report a parentNode, as will elements appended to a document fragment.
The other alternative is to use Node#contains:
document.body.contains(foo)
which essentially does the same thing as scanning the entire DOM for the element:
Array.prototype.some.call(document.querySelector('*'), function(elt) {
return elt === foo;
})
In any case, this all seems pointless, because as far as I can imagine, if you hold a reference to a DOM element, and it's not not in the DOM, then it is in the DOM.
Is there already an element in the place I'm going to be inserting this one?
If you know where the element is going to go, in this case as a child of bar, and that's enough to convince you that the "element already exists", you can check easily enough with something like:
document.getElementById("bar").children.length > 0
Is there already an element with this ID?
As other commenters and responders have noted, you can obviously find an element in the DOM if you have arranged to provide it with some uniquely identifiable characteristics, most likely an id.
I hope it's obvious that element ID is completely separate from the name of any JavaScript variables which happen to be holding references to that element. It is true that elements become available on the root (window) object under their ID or name attributes, a feature best left unused.
Was the element in the source HTML, or created by JavaScript?
From the wording of your question, it seems that you might be interested in whether the element was created by JS, as opposed to originating from the source HTML. There is no way I know of to detect that. If you are intent on doing so, override document.createElement as follows:
document.createElement = (function() {
var old = document.createElement;
return function(tagName) {
var elt = old.call(document, tagName);
elt.I_CREATED_THIS = true;
return elt;
};
}());
> document.body.I_CREATED_THIS
undefined
> elt = document.createElement('span');
> elt.I_CREATED_THIS
true

getElementById of something inside a function, but from outside

I keep learning very simple things about functions, returns, id and everything, so I ran into another problem that looks simple, but I cannot understand why it happens. Check this code:
function test() {
var text = document.createTextNode("Hello");
text.id = "t";
}
var whatIjustwrote = window.document.getElementById("t");
alert(whatIjustwrote);​
Does the getElementById has restrictions to look only for global items? What would be the way to make that alert output the text node inside the function?
Thank you for any comment. The last few days asking things here I have been learning quite a lot!
JSFiddle
Firstly, getElementById will only return an element, and you're creating a text node.
Secondly, it will only return an element that has been added to the DOM. The node you create doesn't get added to the DOM, so it wouldn't be found even if it could be.
Finally, you don't actually call the test function, so the text node isn't even created in memory.
Here's an updated fiddle that demonstrates getElementById actually working:
function test() {
var text = document.createElement("span"); //Create an element
text.innerHTML = "Hello";
text.id = "t";
document.body.appendChild(text); //Add it to the DOM
}
test(); //Invoke the function (so the element actually gets created)
var yourElement = document.getElementById("t"); //Get reference to element
getElementById does only search for element nodes. You did create a text node, which has neither attributes nor an id - you just added a custom property to the JS object. Also, you did not append your node to the document, so it couldn't have been found in the DOM tree.
You might want to read an introduction to the DOM (at MDN), the introduction at quirksmode.org or even the W3 standard itself (especially the introduction section)
function test() {
var elem = document.createElement("span"); // Create an element
var text = document.createTextNode("Hello"); // Create a textnode
elem.appendChild(text); // add text to the element
elem.id = "t"; // assign id to the element
document.body.appendChild(elem); // Add it to the DOM
}
test();
var yourElement = document.getElementById("t"); // Get the element from the DOM
alert(yourElement.textContent); // alerts "Hello"
// you also could have alerted yourElement.firstChild.data - the content of the
// textnode, but only if you had known that yourelement really has a firstchild
(Demo at jsfiddle.net)
A couple of points that come to mind..
1) You cant give a textNode an id attribute (you're actually giving it a new member variable named id)
2) To find an element it must exist in the document's DOM
Do this instead:
var mSpan = document.createElement('span');
mSpan.id = 't';
mSpan.appendChild( document.createTextNode('Hello') );
document.body.appendChild(mSpan);
var whatIjustwrote = window.document.getElementById("t");
alert(whatIjustwrote.innerText);
Does the getElementById has restrictions to look only for global
items?
The answer is no. First you have to define global items anyways. Anything that is attached to the DOM is in fact global, and in terms of global javascript objects there is only one, window, in the case of a browser. You are creating a function but you're never executing it.
In addition the text node cannot actually have an id or any other attribute. You need an element for this, so even if you execute the function you would still get null. Also creating a node does not attach is to the DOM, so you won't be able to access it even if this isn't a text node.
I have updated your fiddle.

How to build a cache of the DOM that does not change

So I tried to build a cache of the DOM:
var DOM = document.getElementsByTagName('*');
However, the DOM variable seems to be a dynamic reference, so that if I change an element in the DOM, the DOM variable changes as well.
I tried iterating through the DOM variable and using the cloneNode method to create a deep copy of each node. This works in that it does not change when I change the DOM. However, the problem is that a cloned node does not equal its original DOM node when you compare them with the === operator.
So to sum up, I'm looking to create a cache of the DOM that does not change but whose nodes are still equal to the original DOM nodes.
document.getElementsByTagName returns a "live" NodeList, which isn't what you think at all. When you access the list, the DOM is traversed (implementation may cache it) every time to get the result. This gives the illusion of the list being live.
document.getElementsByTagName("div") === document.getElementsByTagName("div")
//true
To do what you want, simply convert it to an array. DOM = [].slice.call(DOM)
You seem open to a jQuery solution, so:
$("*")
will return a jQuery object containing all the elements. It will not be updated as the DOM changes.
Or if you just want elements within the <body> (i.e., not <script> or <meta> elements, etc., from the <head>) then:
$("body *")
Being a jQuery object it will of course allow you to access jQuery methods, but you can also access the DOM elements directly with array notation:
var DOM = $("body *");
DOM.show(); // example jQuery method call
alert(DOM.length); // show count of elements in DOM
alert(DOM[4].value) // example of direct access to fifth DOM element
I prefer to use the following methodology:
https://gist.github.com/3841424#file-domcache-js
Or, you may replace the DOM object with a method in this implementation:
var myNS = {
myEventHandler: function(event){
this.DOM.$el.doSomething();
},
cacheDOM: function(){
return {
$el: $("#matrix")
};
},
initialize: function(){
this.DOM = this.cacheDOM();
}
};

Use getElementById for elements that are not [yet] in the DOM?

As far as I know document.getElementById('myId') will only look for HTML elements that are already in the document. Let's say I've created a new element via JS, but that I haven't appended it yet to the document body, is there's a way I can access this element by its id like I would normally do with getElementById?
var newElement = document.createElement('div');
newElement.id = 'myId';
// Without doing: document.body.appendChild(newElement);
var elmt = document.getElementById('myId'); // won't work
Is there a workaround for that?
(I must tell that I don't want to store any reference to this particular element, that's why I need to access it via its Id)
Thank you!
If it isn't part of the document, then you can't grab it using document.getElementById. getElementById does a DOM lookup, so the element must be in the tree to be found. If you create a floating DOM element, it merely exists in memory, and isn't accessible from the DOM. It has to be added to the DOM to be visible.
If you need to reference the element later, simply pass the reference to another function--all objects in JavaScript are passed by reference, so working on that floating DOM element from within another function modifies the original, not a copy.
For anyone stumbling upon this issue in or after 2019, here is an updated answer.
The accepted answer from Andrew Noyes is correct in that document.getElementById won't work unless the element exists in the document and the above code already contains a reference to the desired element anyway.
However, if you can't otherwise retrieve a direct reference to your desired element, consider using selectors. Selectors allow you to retrieve nodes that aren't necessarily in the DOM by using their relationship to other nodes, for example:
var child = document.createElement("div");
child.id = "my_id";
var parent = document.createElement("div");
parent.appendChild(child);
var child2 = parent.querySelector("#my_id");
getElementById is a method on the document object. It's not going to return anything not in the document.
On not storing a reference, huh? If you could magically pull it out of the air by id, then the air would be a reference to it.
If you've created it, just pass the object to other functions and access it directly?
function createDiv()
{
var newElement = document.createElement('div');
doWorkWithDiv(newElement);
}
function doWorkWithDiv(element)
{
element.className = 'newElementCSS';
element.innerHTML = 'Text inside newElement';
addToDoc(element);
}
function addToDoc(element)
{
document.body.appendChild(element);
}

Categories