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

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);
}

Related

Alternative to always referencing to parents and children to modify DOM when using 'this'

I notice that I'm always using this for everything, when I need to share behaviour between components.
Example
I was creating a customised file input component, and I had to return the file that was added by the user with JS therefore. But there were three inputs, and I need to create a function that would be shared among them, so it could not be specific nor unique. It should work for all of'em.
var setFilename = function () {
// get element I want
var input = this
var filepath = input.value
var m = filepath.match(/([^\/\\]+)$/)
var filename = m[1]
var spanLabel = input.parentNode.querySelector('.input')
// apply to element I wanted to get
spanLabel.innerHTML = filename;
}
The problem
Notice the had work just to reach the element I want in a general way. I used parentNode.
I'm always doing that, and there are even codes that finishes like that:
var element = this,
elementParent = this.parentNode,
elementIWant = selectedSpan.parentNode.querySelector('.class');
I dont see it like a good practice. Is it? I don't see it in other developers' code. I did it with jQuery (parent(), closest() etc) and JS.
Is there another approach?
How can I do abstract functions for manipulating DOM the right way? Is that the way people do?
The logic to get a value from an input field and put that value into a target element must assume some kind of DOM structure exists (as in your example) if the target element is not explicitly known.
A convention that I often use is adding a data- (data dash) attribute to the input field to store the id of the target element that will be updated with the input value. For example:
<div>
<label for="filename">Filename: </label>
<input type="text" id="filename" data-target-id="filename-display" />
</div>
<div class="some-displayed-values">
<span class="input" id="filename-display"></span>
</div>
Then, the target element can be selected by its ID value, like so:
function setFilename () {
var input = this;
// older browsers might not have input.dataset available
var targetId = input.dataset.targetId || input.getAttribute('data-target-id');
var target = document.getElementById(targetId);
target.innerHTML = input.value;
}
Example on jsfiddle: http://jsfiddle.net/silkster/ex1dvv0s/
If you need to access the parent, parentNode or parentElement are the right ways.
If other developers don't use them, it may be because they don't want to access the parent.
However, be aware that
parentNode may return a node instead of an element. So using properties or methods only available to elements on the returned value may throw. If you expect the result to be an element, use parentElement instead.
Both parentNode and parentElement may return null. So it may be a good idea to check the returned value before attempting to access its properties.

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

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

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.

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.

getElementById Where Element is dynamically created at runtime

I have created an object at runtime by using innerHTML tag, now I want to access this element by using getElementById, when I accessed the element its return NULL value. Kindly suggest me any direction so that I can acheive this,
Here is the following code hint which I am using
In HTML
<div id="web">
<object id="test"></object>
</div>
In JS
document.getElementById("web").innerHTML="<object id='test2'></object>";
.
.
var obj = document.getElementById("test2");
Here obj return null value.
Did you assign an id to the freshly created element? Did you insert the element into the document tree (using appendChild or insertBefore)? As long as the element is not inserted into the DOM, you can't retrieve it using document.getElementById.
Example of element creation:
var myDiv = document.createElement('div');
myDiv.id = 'myDiv';
document.body.appendChild(myDiv);
document.getElementById('myDiv').innerHTML = 'this should have worked...';
[edit] Given the later supplied code, a third question emerges: is your script located at the bottom of your html page (right before the closing </body> tag)? If it's in the header of the document, your scripting may be running before the document tree is completely rendered. If your script has to be in the header of the document, you could use a load handler to run it after rendering of the document:
window.onload = function(){
document.getElementById("web").innerHTML='<object id="test2"></object>';
// [...]
var obj = document.getElementById('test2');
};
To add an element using JavaScript, you need to do 2 things.
Create the element
var element = document.createElement(tagName);
Add it to the dom
document.body.insertBefore(selector, element);
or
document.getElementByID(selector).appendChild(element);
More info here: MDN
If a DOM node is dynamically created, then there's no need EVER to find it again with document.getElementById().
By creating the node in the right way, you can keep a reference to it as a javascript variable, which can be used anywhere within scope.
For example:
window.onload = function(){
var myDiv = document.createElement('div');
document.body.appendChild(myDiv);
//and now a function that's called in response to some future event
function whatever(){
...
myDiv.style.color = 'red';
...
}
};
Note: The inner function (called at some point(s) future) has access to the myDiv variable because the outer function forms a "closure", within which variables are kept alive and accessible, even though the outer function has completed and returned.

Categories