getElementById working but getElementsByClass not working (JS) [duplicate] - javascript

I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
From this link I could gather that with querySelector I can write document.querySelector(".myclass") to get elements with class myclass and document.querySelector("#myid") to get element with ID myid. But I can already do that getElementsByClassName and getElementById. Which one should be preferred?
Also I work in XPages where the ID is dynamically generated with colon and looks like this view:_id1:inputText1. So when I write document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?

For this answer, I refer to querySelector and querySelectorAll as querySelector* and to getElementById, getElementsByClassName, getElementsByTagName, and getElementsByName as getElement*.
A lot of this information can be verified in the specification, a lot of it is from various benchmarks I ran when I wrote it. The spec: https://dom.spec.whatwg.org/
Main Differences
querySelector* is more flexible, as you can pass it any CSS3 selector, not just simple ones for id, tag, or class.
The performance of querySelector* changes with the size of the DOM that it is invoked on. To be precise, querySelector* calls run in O(n) time and getElement* calls run in O(1) time, where n is the total number of all children of the element or document it is invoked on.
The return types of these calls vary. querySelector and getElementById both return a single element. querySelectorAll and getElementsByName both return NodeLists. The older getElementsByClassName and getElementsByTagName both return HTMLCollections. NodeLists and HTMLCollections are both referred to as collections of elements.
Collections can return "live" or "static" collections respectively. This is NOT reflected in the actual types that they return. getElements* calls return live collections, and querySelectorAll returns a static collection. The way that I understand it, live collections contain references to elements in the DOM, and static collections contain copies of elements. Take a look at #Jan Feldmann's comment's below for a different angle as well. I haven't figured out a good way to incorporate it into my answer but it may be a more accurate understanding.
These concepts are summarized in the following table.
Function | Live? | Type | Time Complexity
querySelector | | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
Details, Tips, and Examples
HTMLCollections are not as array-like as NodeLists and do not support .forEach(). I find the spread operator useful to work around this:
[...document.getElementsByClassName("someClass")].forEach()
Every element, and the global document, have access to all of these functions except for getElementById and getElementsByName, which are only implemented on document.
Chaining getElement* calls instead of using querySelector* will improve performance, especially on very large DOMs. Even on small DOMs and/or with very long chains, it is generally faster. However, unless you know you need the performance, the readability of querySelector* should be preferred. querySelectorAll is often harder to rewrite, because you must select elements from the NodeList or HTMLCollection at every step. For example, the following code does not work:
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections, but if you only wanted one element, then:
document.querySelector("#someId .someClass div")
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of [0] to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with querySelector.
Since all elements have access to both querySelector* and getElement* calls, you can make chains using both calls, which can be useful if you want some performance gain, but cannot avoid a querySelector that can not be written in terms of the getElement* calls.
Though it is generally easy to tell if a selector can be written using only getElement* calls, there is one case that may not be obvious:
document.querySelectorAll(".class1.class2")
can be rewritten as
document.getElementsByClassName("class1 class2")
Using getElement* on a static element fetched with querySelector* will result in an element that is live with respect to the static subset of the DOM copied by querySelector, but not live with respect to the full document DOM... this is where the simple live/static interpretation of elements begins to fall apart. You should probably avoid situations where you have to worry about this, but if you do, remember that querySelector* calls copy elements they find before returning references to them, but getElement* calls fetch direct references without copying.
querySelector* and getElementById traverse elements in preorder, depth-first, called "tree order" in the specification. With other getElement* calls it is not clear to me from the specification - they may be the same as tree order, but getElementsByClassName(".someClass")[0] may not reliably give the same result in every browser. getElementById("#someId") should though, even if you have multiple copies of the same id on your page.
I was working on an infinite scroll page when I had to look into this, and I think that is likely to be a common case where performance becomes an issue. Our code had onScroll events with querySelectorAll calls in them. Even if the calls were rate limited, the page would break if you scrolled down far enough, at which point there would be too many calls iterating through too many elements for the browser to keep up. The size of the DOM is relevant in this use case, and so there's a good case for preferring getElement* calls in code that runs on an infinite scroll page.

I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
The syntax and the browser support.
querySelector is more useful when you want to use more complex selectors.
e.g. All list items descended from an element that is a member of the foo class: .foo li
document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
The : character has special meaning inside a selector. You have to escape it. (The selector escape character has special meaning in a JS string too, so you have to escape that too).
document.querySelector("#view\\:_id1\\:inputText1")

collecting from Mozilla Documentation:
The NodeSelector interface
This specification adds two new methods to any objects implementing the Document, DocumentFragment, or Element interfaces:
querySelector
Returns the first matching Element node within the node's subtree. If
no matching node is found, null is returned.
querySelectorAll
Returns a NodeList containing all matching Element nodes within the
node's subtree, or an empty NodeList if no matches are found.
and
Note: The NodeList returned by querySelectorAll() is not live, which
means that changes in the DOM are not reflected in the collection.
This is different from other DOM querying methods that return live
node lists.

About the differences, there is an important one in the results between querySelectorAll and getElementsByClassName: the return value is different. querySelectorAll will return a static collection, while getElementsByClassName returns a live collection. This could lead to confusion if you store the results in a variable for later use:
A variable generated with querySelectorAll will contain the elements that fulfilled the selector at the moment the method was called.
A variable generated with getElementsByClassName will contain the elements that fulfilled the selector when it is used (that may be different from the moment the method was called).
For example, notice how even if you haven't reassigned the variables aux1 and aux2, they contain different values after updating the classes:
// storing all the elements with class "blue" using the two methods
var aux1 = document.querySelectorAll(".blue");
var aux2 = document.getElementsByClassName("blue");
// write the number of elements in each array (values match)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
// change one element's class to "blue"
document.getElementById("div1").className = "blue";
// write the number of elements in each array (values differ)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>

I came to this page purely to find out the better method to use in terms of performance - i.e. which is faster:
querySelector / querySelectorAll or getElementsByClassName
and I found this:
https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18
It runs a test on the 2 x examples above, plus it chucks in a test for jQuery's equivalent selector as well. my test results were as follows:
getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec

querySelector can be a complete CSS(3)-Selector with IDs and Classes and Pseudo-Classes together like this:
'#id.class:pseudo'
// or
'tag #id .class .class.class'
with getElementsByClassName you can just define a class
'class'
with getElementById you can just define an id
'id'

querySelector and querySelectorAll are a relatively new APIs, whereas getElementById and getElementsByClassName have been with us for a lot longer. That means that what you use will mostly depend on which browsers you need to support.
As for the :, it has a special meaning so you have to escape it if you have to use it as a part of a ID/class name.

querySelector is of w3c Selector API
getElementBy is of w3c DOM API
IMO the most notable difference is that the return type of querySelectorAll is a static node list and for getElementsBy it's a live node list. Therefore the looping in demo 2 never ends because lis is live and updates itself during each iteration.
// Demo 1 correct
var ul = document.querySelectorAll('ul')[0],
lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}
// Demo 2 wrong
var ul = document.getElementsByTagName('ul')[0],
lis = ul.getElementsByTagName("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}

Difference between "querySelector" and "querySelectorAll"
//querySelector returns single element
let listsingle = document.querySelector('li');
console.log(listsingle);
//querySelectorAll returns lit/array of elements
let list = document.querySelectorAll('li');
console.log(list);
//Note : output will be visible in Console
<ul>
<li class="test">ffff</li>
<li class="test">vvvv</li>
<li>dddd</li>
<li class="test">ddff</li>
</ul>

look at this
https://codepen.io/bagdaulet/pen/bzdKjL
getElementById fastest than querySelector on 25%
jquery is slowest
var q = time_my_script(function() {
for (i = 0; i < 1000000; i++) {
var w = document.querySelector('#ll');
}
});
console.log('querySelector: '+q+'ms');

The main difference between querySelector and getlementbyID(Claassname,Tagname etc) is if there is more than one elements which satifies the condition querySelector will return only one output whereas getElementBy* will return all the elements.
Lets consider an example to make it more clear.
<nav id="primary" class="menu">
<a class="link" href="#">For Business</a>
<a class="link" href="#">Become an Instructor</a>
<a class="link" href="#">Mobile Applications</a>
<a class="link" href="#">Support</a>
<a class="link" href="#">Help</a>
</nav>
Below code will explain the difference
**QUERY SELECTOR**
document.querySelector('.link'); // Output : For Business (element)
document.querySelectorAll('.link'); //Out All the element with class link
**GET ELEMENT**
document.getElementsByClassName('link') // Output : will return all the element with a class "link" but whereas in query selector it will return only one element which encounters first.
Inshort if we want to select single element go for queryslector or if we want multiple element go for getElement

Related

My querySelectorAll can't select more than 1 item [duplicate]

I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
From this link I could gather that with querySelector I can write document.querySelector(".myclass") to get elements with class myclass and document.querySelector("#myid") to get element with ID myid. But I can already do that getElementsByClassName and getElementById. Which one should be preferred?
Also I work in XPages where the ID is dynamically generated with colon and looks like this view:_id1:inputText1. So when I write document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
For this answer, I refer to querySelector and querySelectorAll as querySelector* and to getElementById, getElementsByClassName, getElementsByTagName, and getElementsByName as getElement*.
A lot of this information can be verified in the specification, a lot of it is from various benchmarks I ran when I wrote it. The spec: https://dom.spec.whatwg.org/
Main Differences
querySelector* is more flexible, as you can pass it any CSS3 selector, not just simple ones for id, tag, or class.
The performance of querySelector* changes with the size of the DOM that it is invoked on. To be precise, querySelector* calls run in O(n) time and getElement* calls run in O(1) time, where n is the total number of all children of the element or document it is invoked on.
The return types of these calls vary. querySelector and getElementById both return a single element. querySelectorAll and getElementsByName both return NodeLists. The older getElementsByClassName and getElementsByTagName both return HTMLCollections. NodeLists and HTMLCollections are both referred to as collections of elements.
Collections can return "live" or "static" collections respectively. This is NOT reflected in the actual types that they return. getElements* calls return live collections, and querySelectorAll returns a static collection. The way that I understand it, live collections contain references to elements in the DOM, and static collections contain copies of elements. Take a look at #Jan Feldmann's comment's below for a different angle as well. I haven't figured out a good way to incorporate it into my answer but it may be a more accurate understanding.
These concepts are summarized in the following table.
Function | Live? | Type | Time Complexity
querySelector | | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
Details, Tips, and Examples
HTMLCollections are not as array-like as NodeLists and do not support .forEach(). I find the spread operator useful to work around this:
[...document.getElementsByClassName("someClass")].forEach()
Every element, and the global document, have access to all of these functions except for getElementById and getElementsByName, which are only implemented on document.
Chaining getElement* calls instead of using querySelector* will improve performance, especially on very large DOMs. Even on small DOMs and/or with very long chains, it is generally faster. However, unless you know you need the performance, the readability of querySelector* should be preferred. querySelectorAll is often harder to rewrite, because you must select elements from the NodeList or HTMLCollection at every step. For example, the following code does not work:
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections, but if you only wanted one element, then:
document.querySelector("#someId .someClass div")
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of [0] to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with querySelector.
Since all elements have access to both querySelector* and getElement* calls, you can make chains using both calls, which can be useful if you want some performance gain, but cannot avoid a querySelector that can not be written in terms of the getElement* calls.
Though it is generally easy to tell if a selector can be written using only getElement* calls, there is one case that may not be obvious:
document.querySelectorAll(".class1.class2")
can be rewritten as
document.getElementsByClassName("class1 class2")
Using getElement* on a static element fetched with querySelector* will result in an element that is live with respect to the static subset of the DOM copied by querySelector, but not live with respect to the full document DOM... this is where the simple live/static interpretation of elements begins to fall apart. You should probably avoid situations where you have to worry about this, but if you do, remember that querySelector* calls copy elements they find before returning references to them, but getElement* calls fetch direct references without copying.
querySelector* and getElementById traverse elements in preorder, depth-first, called "tree order" in the specification. With other getElement* calls it is not clear to me from the specification - they may be the same as tree order, but getElementsByClassName(".someClass")[0] may not reliably give the same result in every browser. getElementById("#someId") should though, even if you have multiple copies of the same id on your page.
I was working on an infinite scroll page when I had to look into this, and I think that is likely to be a common case where performance becomes an issue. Our code had onScroll events with querySelectorAll calls in them. Even if the calls were rate limited, the page would break if you scrolled down far enough, at which point there would be too many calls iterating through too many elements for the browser to keep up. The size of the DOM is relevant in this use case, and so there's a good case for preferring getElement* calls in code that runs on an infinite scroll page.
I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
The syntax and the browser support.
querySelector is more useful when you want to use more complex selectors.
e.g. All list items descended from an element that is a member of the foo class: .foo li
document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
The : character has special meaning inside a selector. You have to escape it. (The selector escape character has special meaning in a JS string too, so you have to escape that too).
document.querySelector("#view\\:_id1\\:inputText1")
collecting from Mozilla Documentation:
The NodeSelector interface
This specification adds two new methods to any objects implementing the Document, DocumentFragment, or Element interfaces:
querySelector
Returns the first matching Element node within the node's subtree. If
no matching node is found, null is returned.
querySelectorAll
Returns a NodeList containing all matching Element nodes within the
node's subtree, or an empty NodeList if no matches are found.
and
Note: The NodeList returned by querySelectorAll() is not live, which
means that changes in the DOM are not reflected in the collection.
This is different from other DOM querying methods that return live
node lists.
About the differences, there is an important one in the results between querySelectorAll and getElementsByClassName: the return value is different. querySelectorAll will return a static collection, while getElementsByClassName returns a live collection. This could lead to confusion if you store the results in a variable for later use:
A variable generated with querySelectorAll will contain the elements that fulfilled the selector at the moment the method was called.
A variable generated with getElementsByClassName will contain the elements that fulfilled the selector when it is used (that may be different from the moment the method was called).
For example, notice how even if you haven't reassigned the variables aux1 and aux2, they contain different values after updating the classes:
// storing all the elements with class "blue" using the two methods
var aux1 = document.querySelectorAll(".blue");
var aux2 = document.getElementsByClassName("blue");
// write the number of elements in each array (values match)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
// change one element's class to "blue"
document.getElementById("div1").className = "blue";
// write the number of elements in each array (values differ)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>
I came to this page purely to find out the better method to use in terms of performance - i.e. which is faster:
querySelector / querySelectorAll or getElementsByClassName
and I found this:
https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18
It runs a test on the 2 x examples above, plus it chucks in a test for jQuery's equivalent selector as well. my test results were as follows:
getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
querySelector can be a complete CSS(3)-Selector with IDs and Classes and Pseudo-Classes together like this:
'#id.class:pseudo'
// or
'tag #id .class .class.class'
with getElementsByClassName you can just define a class
'class'
with getElementById you can just define an id
'id'
querySelector and querySelectorAll are a relatively new APIs, whereas getElementById and getElementsByClassName have been with us for a lot longer. That means that what you use will mostly depend on which browsers you need to support.
As for the :, it has a special meaning so you have to escape it if you have to use it as a part of a ID/class name.
querySelector is of w3c Selector API
getElementBy is of w3c DOM API
IMO the most notable difference is that the return type of querySelectorAll is a static node list and for getElementsBy it's a live node list. Therefore the looping in demo 2 never ends because lis is live and updates itself during each iteration.
// Demo 1 correct
var ul = document.querySelectorAll('ul')[0],
lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}
// Demo 2 wrong
var ul = document.getElementsByTagName('ul')[0],
lis = ul.getElementsByTagName("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}
Difference between "querySelector" and "querySelectorAll"
//querySelector returns single element
let listsingle = document.querySelector('li');
console.log(listsingle);
//querySelectorAll returns lit/array of elements
let list = document.querySelectorAll('li');
console.log(list);
//Note : output will be visible in Console
<ul>
<li class="test">ffff</li>
<li class="test">vvvv</li>
<li>dddd</li>
<li class="test">ddff</li>
</ul>
look at this
https://codepen.io/bagdaulet/pen/bzdKjL
getElementById fastest than querySelector on 25%
jquery is slowest
var q = time_my_script(function() {
for (i = 0; i < 1000000; i++) {
var w = document.querySelector('#ll');
}
});
console.log('querySelector: '+q+'ms');
The main difference between querySelector and getlementbyID(Claassname,Tagname etc) is if there is more than one elements which satifies the condition querySelector will return only one output whereas getElementBy* will return all the elements.
Lets consider an example to make it more clear.
<nav id="primary" class="menu">
<a class="link" href="#">For Business</a>
<a class="link" href="#">Become an Instructor</a>
<a class="link" href="#">Mobile Applications</a>
<a class="link" href="#">Support</a>
<a class="link" href="#">Help</a>
</nav>
Below code will explain the difference
**QUERY SELECTOR**
document.querySelector('.link'); // Output : For Business (element)
document.querySelectorAll('.link'); //Out All the element with class link
**GET ELEMENT**
document.getElementsByClassName('link') // Output : will return all the element with a class "link" but whereas in query selector it will return only one element which encounters first.
Inshort if we want to select single element go for queryslector or if we want multiple element go for getElement

How to extract all links from a particular page and place them into an array with JavaScript?

Honestly, I don't know where to start with "extracting." My best guess would be to use the basic .html() tag from JQuery to solve this problem. This is for a small project to improve my JavaScript skills. Any ideas on how this could be done? Thanks so much...
I apologize for being unclear. I meant extracting all the links from a particular page from a domain I don't own. Then, putting these links into an array. Thanks!
Well, this comes to mind ?
var arr = [].slice.call( document.querySelectorAll('a') );
It gets all the matching elements with querySelectorAll, and converts the returned nodeList to an array using [].slice.call, where [] is a shortcut for Array.prototype. In other words it calls the native Array.slice method with call(), passing the elements in as the this value, effectively creating an array from the elements.
if you need the HTML, and not the DOM elements, you can map the elements array and return the outerHTML
var markup = arr.map(function(elem) { return elem.outerHTML; });
or if you just need the URL's, you can run the same map and return the href attribute instead
var urls = arr.map(function(elem) { return elem.getAttribute('href'); });
You don't necessarily need jQuery for this and if learning Javascript is your goal you might be better off without using it for now. querySelectorAll is available in all modern browsers and can accomplish what you are looking for. Per the documentation:
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
A NodeList is not an array however so you would need to do a little extra work to make an array of the link elements. You can read in the documentation why they are different.
The selectors used in the method are CSS Selectors and you can checkout the documentation for querySelector for examples.
So to do what you want you could do something like:
var a_list = document.querySelectorAll('a'); // returns NodeList
var a_array = Array.prototype.slice.call(a_list); // converts NodeList to Array
If the jQuery is an acceptable option, you can get all the links by a simple
var links = $('a[href]');
The "links" is an array already.
I would also fiddle around with something like this.
Array.prototype.slice.call(document.querySelectorAll('a'));
Googling it would be a good start so you can learn more about how it works and use it to your advantage.

Javascript querySelector or getElementById [duplicate]

I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
From this link I could gather that with querySelector I can write document.querySelector(".myclass") to get elements with class myclass and document.querySelector("#myid") to get element with ID myid. But I can already do that getElementsByClassName and getElementById. Which one should be preferred?
Also I work in XPages where the ID is dynamically generated with colon and looks like this view:_id1:inputText1. So when I write document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
For this answer, I refer to querySelector and querySelectorAll as querySelector* and to getElementById, getElementsByClassName, getElementsByTagName, and getElementsByName as getElement*.
A lot of this information can be verified in the specification, a lot of it is from various benchmarks I ran when I wrote it. The spec: https://dom.spec.whatwg.org/
Main Differences
querySelector* is more flexible, as you can pass it any CSS3 selector, not just simple ones for id, tag, or class.
The performance of querySelector* changes with the size of the DOM that it is invoked on. To be precise, querySelector* calls run in O(n) time and getElement* calls run in O(1) time, where n is the total number of all children of the element or document it is invoked on.
The return types of these calls vary. querySelector and getElementById both return a single element. querySelectorAll and getElementsByName both return NodeLists. The older getElementsByClassName and getElementsByTagName both return HTMLCollections. NodeLists and HTMLCollections are both referred to as collections of elements.
Collections can return "live" or "static" collections respectively. This is NOT reflected in the actual types that they return. getElements* calls return live collections, and querySelectorAll returns a static collection. The way that I understand it, live collections contain references to elements in the DOM, and static collections contain copies of elements. Take a look at #Jan Feldmann's comment's below for a different angle as well. I haven't figured out a good way to incorporate it into my answer but it may be a more accurate understanding.
These concepts are summarized in the following table.
Function | Live? | Type | Time Complexity
querySelector | | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
Details, Tips, and Examples
HTMLCollections are not as array-like as NodeLists and do not support .forEach(). I find the spread operator useful to work around this:
[...document.getElementsByClassName("someClass")].forEach()
Every element, and the global document, have access to all of these functions except for getElementById and getElementsByName, which are only implemented on document.
Chaining getElement* calls instead of using querySelector* will improve performance, especially on very large DOMs. Even on small DOMs and/or with very long chains, it is generally faster. However, unless you know you need the performance, the readability of querySelector* should be preferred. querySelectorAll is often harder to rewrite, because you must select elements from the NodeList or HTMLCollection at every step. For example, the following code does not work:
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections, but if you only wanted one element, then:
document.querySelector("#someId .someClass div")
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of [0] to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with querySelector.
Since all elements have access to both querySelector* and getElement* calls, you can make chains using both calls, which can be useful if you want some performance gain, but cannot avoid a querySelector that can not be written in terms of the getElement* calls.
Though it is generally easy to tell if a selector can be written using only getElement* calls, there is one case that may not be obvious:
document.querySelectorAll(".class1.class2")
can be rewritten as
document.getElementsByClassName("class1 class2")
Using getElement* on a static element fetched with querySelector* will result in an element that is live with respect to the static subset of the DOM copied by querySelector, but not live with respect to the full document DOM... this is where the simple live/static interpretation of elements begins to fall apart. You should probably avoid situations where you have to worry about this, but if you do, remember that querySelector* calls copy elements they find before returning references to them, but getElement* calls fetch direct references without copying.
querySelector* and getElementById traverse elements in preorder, depth-first, called "tree order" in the specification. With other getElement* calls it is not clear to me from the specification - they may be the same as tree order, but getElementsByClassName(".someClass")[0] may not reliably give the same result in every browser. getElementById("#someId") should though, even if you have multiple copies of the same id on your page.
I was working on an infinite scroll page when I had to look into this, and I think that is likely to be a common case where performance becomes an issue. Our code had onScroll events with querySelectorAll calls in them. Even if the calls were rate limited, the page would break if you scrolled down far enough, at which point there would be too many calls iterating through too many elements for the browser to keep up. The size of the DOM is relevant in this use case, and so there's a good case for preferring getElement* calls in code that runs on an infinite scroll page.
I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
The syntax and the browser support.
querySelector is more useful when you want to use more complex selectors.
e.g. All list items descended from an element that is a member of the foo class: .foo li
document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
The : character has special meaning inside a selector. You have to escape it. (The selector escape character has special meaning in a JS string too, so you have to escape that too).
document.querySelector("#view\\:_id1\\:inputText1")
collecting from Mozilla Documentation:
The NodeSelector interface
This specification adds two new methods to any objects implementing the Document, DocumentFragment, or Element interfaces:
querySelector
Returns the first matching Element node within the node's subtree. If
no matching node is found, null is returned.
querySelectorAll
Returns a NodeList containing all matching Element nodes within the
node's subtree, or an empty NodeList if no matches are found.
and
Note: The NodeList returned by querySelectorAll() is not live, which
means that changes in the DOM are not reflected in the collection.
This is different from other DOM querying methods that return live
node lists.
About the differences, there is an important one in the results between querySelectorAll and getElementsByClassName: the return value is different. querySelectorAll will return a static collection, while getElementsByClassName returns a live collection. This could lead to confusion if you store the results in a variable for later use:
A variable generated with querySelectorAll will contain the elements that fulfilled the selector at the moment the method was called.
A variable generated with getElementsByClassName will contain the elements that fulfilled the selector when it is used (that may be different from the moment the method was called).
For example, notice how even if you haven't reassigned the variables aux1 and aux2, they contain different values after updating the classes:
// storing all the elements with class "blue" using the two methods
var aux1 = document.querySelectorAll(".blue");
var aux2 = document.getElementsByClassName("blue");
// write the number of elements in each array (values match)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
// change one element's class to "blue"
document.getElementById("div1").className = "blue";
// write the number of elements in each array (values differ)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>
I came to this page purely to find out the better method to use in terms of performance - i.e. which is faster:
querySelector / querySelectorAll or getElementsByClassName
and I found this:
https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18
It runs a test on the 2 x examples above, plus it chucks in a test for jQuery's equivalent selector as well. my test results were as follows:
getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
querySelector can be a complete CSS(3)-Selector with IDs and Classes and Pseudo-Classes together like this:
'#id.class:pseudo'
// or
'tag #id .class .class.class'
with getElementsByClassName you can just define a class
'class'
with getElementById you can just define an id
'id'
querySelector and querySelectorAll are a relatively new APIs, whereas getElementById and getElementsByClassName have been with us for a lot longer. That means that what you use will mostly depend on which browsers you need to support.
As for the :, it has a special meaning so you have to escape it if you have to use it as a part of a ID/class name.
querySelector is of w3c Selector API
getElementBy is of w3c DOM API
IMO the most notable difference is that the return type of querySelectorAll is a static node list and for getElementsBy it's a live node list. Therefore the looping in demo 2 never ends because lis is live and updates itself during each iteration.
// Demo 1 correct
var ul = document.querySelectorAll('ul')[0],
lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}
// Demo 2 wrong
var ul = document.getElementsByTagName('ul')[0],
lis = ul.getElementsByTagName("li");
for(var i = 0; i < lis.length ; i++){
ul.appendChild(document.createElement("li"));
}
Difference between "querySelector" and "querySelectorAll"
//querySelector returns single element
let listsingle = document.querySelector('li');
console.log(listsingle);
//querySelectorAll returns lit/array of elements
let list = document.querySelectorAll('li');
console.log(list);
//Note : output will be visible in Console
<ul>
<li class="test">ffff</li>
<li class="test">vvvv</li>
<li>dddd</li>
<li class="test">ddff</li>
</ul>
look at this
https://codepen.io/bagdaulet/pen/bzdKjL
getElementById fastest than querySelector on 25%
jquery is slowest
var q = time_my_script(function() {
for (i = 0; i < 1000000; i++) {
var w = document.querySelector('#ll');
}
});
console.log('querySelector: '+q+'ms');
The main difference between querySelector and getlementbyID(Claassname,Tagname etc) is if there is more than one elements which satifies the condition querySelector will return only one output whereas getElementBy* will return all the elements.
Lets consider an example to make it more clear.
<nav id="primary" class="menu">
<a class="link" href="#">For Business</a>
<a class="link" href="#">Become an Instructor</a>
<a class="link" href="#">Mobile Applications</a>
<a class="link" href="#">Support</a>
<a class="link" href="#">Help</a>
</nav>
Below code will explain the difference
**QUERY SELECTOR**
document.querySelector('.link'); // Output : For Business (element)
document.querySelectorAll('.link'); //Out All the element with class link
**GET ELEMENT**
document.getElementsByClassName('link') // Output : will return all the element with a class "link" but whereas in query selector it will return only one element which encounters first.
Inshort if we want to select single element go for queryslector or if we want multiple element go for getElement

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