Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getElementsByTagName("*") always updated?

I have made this code:

var foo=document.createElement("div");

var childs=foo.getElementsByTagName("*");

console.log(childs.length);//0 OK

var a=document.createElement("a");

foo.appendChild(a);

console.log(childs.length);//1 WTF?

A fiddle: http://jsfiddle.net/RL54Z/3/

I don't have to write childs=foo.getElementsByTagName("*"); between the fifth and the sixth line so that childs.length is updated.

How can it be?

like image 527
Mageek Avatar asked Jun 30 '12 05:06

Mageek


People also ask

What getElementsByTagName returns?

getElementsByTagName() method returns a live HTMLCollection of elements with the given tag name. All descendants of the specified element are searched, but not the element itself. The returned list is live, which means it updates itself with the DOM tree automatically.

What is the syntax of getElementsByTagName()?

The getElementsByTagName() method in HTML returns the collection of all the elements in the document with the given tag name. To extract any info just iterate through all the elements using the length property. Syntax: var elements = document.

Does getElementsByTagName return an array?

getElementsByTagName - the method name itself implies that it will return multiple elements - i.e. an array. The method always returns an array, with the length equal to the number of matching elements. As such you must always access the elements by the index of the element in the array.

How to get all tag name in JavaScript?

The getElementsByTagName() method returns a collection of all elements with a specified tag name. The getElementsByTagName() method returns an HTMLCollection. The getElementsByTagName() property is read-only.


2 Answers

Most lists of nodes in the DOM (e.g. returned from getElementsBy*, querySelectorAll, and Node.childNodes) are not simple Arrays but rather NodeList objects. NodeList objects are usually "live", in that changes to the document are automatically propagated to the Nodelist object. (An exception is the result from querySelectorAll, which is not live!)

So as you can see in your example, if you retrieve a NodeList of all a elements, then add another a element to the document, that a will appear in your NodeList object.

This is why it is unsafe to iterate through a NodeList while making changes to the document at the same time. E.g., this code will behave in surprising ways:

var NodeListA = document.getElementsByTagName('a');

for (var i=0; i<NodeListA.length; ++i) {
   // UNSAFE: don't do this!
   NodeListA[i].parentNode.removeChild(NodeListA[i]);
}

What will happen is you will end up skipping elements! Either iterate backwards from the end of the NodeList, or copy the NodeList to a plain Array (which will not update) and then work with that.

Read more about NodeLists at the Mozilla MDC site.

like image 95
Francis Avila Avatar answered Sep 28 '22 08:09

Francis Avila


If you read the documentation you wouldn't be surprised

Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments.

like image 29
Musa Avatar answered Sep 28 '22 06:09

Musa