NodeList changes do not affect length - javascript

i have created a NodeList with nodeList = document.createDocumentFragment().childNodes;,
then i have set nodeList[0] = document.getElementById("foo");
everything works fine, the only problem is, that nodeList.length stays 0
i have allready tried to change an Array to a NodeList. Also i have tried to use a fragment, appended children and changed them afterwards and returned the childnodes.
i cannot just append the original children, because they get removed somewere else then.
what am i missing?
yes i know i could just use an Array, but i want to NodeList element

I am not sure how duplicate works so i will add answer here
from documentation https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment?redirectlocale=en-US&redirectslug=DOM%2FDocumentFragment DocumentFragment has child property as read only so you cant write to it, instead use appendChild();
var nodeList = document.createDocumentFragment();
nodeList.appendChild(document.getElementById("foo"))

Related

Uncaught TypeError: Cannot read property 'style' of null at HTMLUListElement.<anonymous> [duplicate]

How do I get only one DOM element by class name? I am guessing that the syntax of getting elements by class name is getElementsByClassName, but I am not sure how many elements it's going to return.
document.getElementsByClassName('className') would always return multiple elements because conceptually Classes are meant to be applied to multiple elements. If you want only the first element in the DOM with that class, you can select the first element out of the array-like HTMLCollection returned.
var elements = document.getElementsByClassName('className');
var requiredElement = elements[0];
Else, if you really want to select only one element. Then you need to use 'id' as conceptually it is used as an identifier for unique elements in a Web Page.
// HTML
<div id="myElement"></div>
// JS
var requiredElement = document.getElementById('myElement');
Clarifications :
getElementsByClassName returns a Node List and not an array
You do not need jQuery
What you were looking for was probably document.querySelector :
How do I get only one DOM element by class name?
var firstElementWithClass = document.querySelector('.myclass');
Also see: https://developer.mozilla.org/en/docs/Web/API/Document/querySelector
You can use jQuery:
$('.className').eq(index)
Or you can use the javascript built-in method:
var elements = document.getElementsByClassName('className');
This returns a nodeList of elements that you can iterate and make what you want.
If you want only one, you can access the elements in the javascript version like this:
elements[index]
To anyone looking for a one liner
var first = document.getElementsByClassName('test')[0];
Use NodeList.item().
For example:
var first = getElementsByClassName('test').item(0);
You can try with this:
document.getElementsByClassName("className")[index]

Bracket notation dosent work for document.querySelector

I want to remove the third div element inside the body of the page by setting its style to display:none; and using querySelector with a bracket notation to get the element, but my code returns a error
"TypeError: el is undefined"
and when I try to console.log("el") it returns undefined
I've tried using let, const except of var and some other things
var el = document.querySelector("div")[3]
el.style.display = "none"
It should remove the third div in the page.
You're facing two issues:
The querySelector() method is for accessing a single DOM node. If you intend on working with more than one element, you can use document.querySelectorAll() method which returns a node list
The other issue is to remember that arrays use zero based numbering, meaning [3] accesses the fourth element, not the third. The count starts at zero.
With these two points in mind, what you're looking for is:
var el = document.querySelectorAll("div")[2]; // for the third div
el.style.display = "none";
I'm just going to summarise #Sirko and #CoreyOgburn comments:
Don't use document.querySelector, it returns a single node, instead, use document.getElementsbyTagName (my suggestion) or stick with document.querySelectorAll("div"), which returns an Array of all div nodes on the site. Alternatively, use JQuery. And also, if you want to get the third element, you have to type document.querySelectorAll("div")[2], not [3].

Why is [0] needed for getElementsByClassName to work when there's only one class to select?

I tried using let modal = document.getElementsByClassName('modal') to select an element with the class modal. It only worked after using node selection to select the first result: let modal = document.getElementsByClassName('modal')[0]. I know the method Document.getElementsByClassName() returns child elements which have all of the given class names, but there's only one element in my HTML with that class. I confirmed this in my browser's dev tools by using var x = document.getElementsByClassName('modal').length and logging the value of x to the console (it returned 1 as expected).
Could someone explain why node selection is needed in this case?
Edit: My question is different than the one marked as a duplicate. In that question, they are asking the difference between methods than return a single element and those that return an array-like collection of elements. I'm already aware getElementsByClassName returns an array-like collection of elements, whereas the other methods return one element. My question is why do you need to specify the index in a case where all elements of a class are returned but there's only one element with a class (so one item, the correct item, is returned).
document.getElementsByClassName will return a list of elements with the given class name. Even if there is only one element with that class name it will be in a Node List which is why you have to use the [0]
It is needed because getElementsByClassName Returns an HTMLCollection and not a single element.
To get the item without using [0], use a query selector instead, this will give you the item instead of a collection of items.
let modal = document.querySelector('.modal')
console.log(modal)
document.getElementsByClassName
will return array of element who has this class

How to get control id from Object HTML Collection?

I want to get the control id so that I can attach event to this id,code for this is:
var t=document.getElementsByName('test');
alert(t);
this 't' here returns the Object HTMLCollection but when I run this code on jsfiddle i got Object NodeList and by using t[0].id I got the required id.
I have some requirement so I don't want to use document.getElementById();
Can any one tell me why this is happening and how can I get the id of control through Object HTMLCollection?
So it looks like you have two questions:
1) Can any one tell me why this is happening
and
2) how can I get the id of control through Object HTMLCollection?
First I think you need to understand WHAT an HTMLCollection is. Please read the answer to this stackoverflow question and pay careful attention to what is written, specifically
getElementsByTagName is method of the DOM interface. It accepts a tag
name as input and returns a NodeList (some browsers chose to return
HTMLCollection instead, which is OK, since it is a superset of
NodeList).
So the two share most properties, especially basic properties like id. I recommend reading up on HTMLCollection and NodeList on MDN.
This also contains the answer to your question as to WHY this happens
getElementsByTagName is method of the DOM interface. It accepts a tag
name as input and returns a NodeList (some browsers chose to return
HTMLCollection instead, which is OK, since it is a superset of
NodeList).
Essentially, the answer is simply that different browsers behave differently (when it comes to web development, you will find this is true in MANY ways).
So onto a more deailed answer to the second part of your question. ASSUMING that you have HTML elements with the name 'test' and ASSUMING you want the first one, all you have to do is reference the first element of the returned array, whether it is a NodeList or an HTMLCollection
var element = document.getElementsByName('test')[0];
If you want to make sure you got elements back, just get the array and check that it has > 0 elements
var element;
var elements = document.getElementsByName('test');
if (elements.length > 0)
{
element = elements[0];
}
The method you are using will return an array, so to answer your question you will need to do:
var element = document.getElementsByName('test')[0];

classList.remove is removing elements from a HTMLCollection?

I'm encountering some very strange behaviour with JavaScripts new classList API, say we have the following HTML code:
<p class="testing">Lorem Ipsum</p>
<p class="testing">Lorem Ipsum</p>
And the following JavaScript code:
var elements = document.getElementsByClassName("testing");
alert(elements.length);
elements[0].classList.remove("testing");
alert(elements.length);
The first alert will give you a value of 2, whilst the second alert returns 1.
It appears that removing the class from the element is also removing it from the elements HTMLCollection, which makes absolutely no sense to me.
You can see an example of this code HERE.
I encountered this problem when trying to remove a certain class from some elements using code like below:
var elements = document.getElementsByClassName('testing');
var elementsLength = elements.length - 1;
for(var i = 0; i <= elementsLength ; i++)
{
elements[i].classList.remove('testing');
}
Say we have two elements like in the example above, the loop runs successfully the first time, but the second time it's looking for an element in the HTMLCollection that no longer exists, so I get something like "TypeError: elements[i] is undefined".
You can see an example of the above code HERE
This is frustrating to say the least, I can't understand why/how classList.remove could effect what is effectively an array set only once before the classList.remove function is called. I can't even seem to find anything about this behaviour online.
Am I doing something crazy? Or has I unearthed some strange hidden feature of the classList api that no one knows about?
The collection returned by document.getElementsByClassName is live so if an element doesn't have that class anymore it will be removed from the collection.
You can either create a non-live copy of the collection:
var elements = [].slice.call(document.getElementsByClassName('testing'));
Or take in account that it's live:
while (elements.length) elements[0].classList.remove('element-focus');
Using document.getElementsByClassName returns a live HTMLCollection:
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
Thus (as described in plalx's answer) if you remove an element's class, the element is removed from an HTMLCollection based on that class.
Instead you could use document.querySelectorAll which returns a static NodeList collection:
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
So your code would change from
var elements = document.getElementsByClassName("testing");
with the class name "testing" as an argument, to
var elements = document.querySelectorAll(".testing");
with the class selector ".testing" as an argument.
And then you could iterate over elements which would be a static NodeList.

Categories