QuerySelectorAll not working

I have a requirement when I have to take the last .div into a container and apply some business logic to it. The selection of the last .div should be dynamic, since the user has the ability to add / remove .div elements.

At first I tried with querySelectorAll , but it did not seem to work. So I decided to change it to getElementsByClassName and it is amazing that it worked with the same logic. Can someone please help me on the reason why remove_div not working and the second ( remove_div_2 )?

Note. I am not looking for a fix / solution to the problem, because I already went through the second option. I just want to know why the querySelectorAll option querySelectorAll not work.

Below is my code:

HTML:

 <div id='container'> <div id='div1' class='div'>This is Div 1</div> <div id='div2' class='div'>This is Div 2</div> <div id='div3' class='div'>This is Div 3</div> </div> <button type='button' id='append_div'>Append Div</button> <button type='button' id='remove_div'>Remove Div</button> <button type='button' id='remove_div_2'>Remove Div 2</button> 

JavaScript:

 window.onload = function () { var elementToStyle = document.querySelectorAll("#container .div"); elementToStyle[elementToStyle.length - 1].classList.add('red'); document.getElementById('append_div').onclick = function () { var divToInsert = document.createElement('div'); divToInsert.id = 'new_div'; divToInsert.className = 'div'; divToInsert.innerHTML = 'This is an appended div'; document.getElementById('container').appendChild(divToInsert); var elToStyle = document.querySelectorAll("#container .div"); for (i = 0; i < elToStyle.length; i++) elToStyle[i].classList.remove('red'); elToStyle[elToStyle.length - 1].classList.add('red'); }; document.getElementById('remove_div').onclick = function () { var elToStyle = document.querySelectorAll("#container .div"); document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]); elToStyle[elToStyle.length - 1].classList.add('red'); }; document.getElementById('remove_div_2').onclick = function () { var elToStyle = document.getElementsByClassName('div'); document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]); elToStyle[elToStyle.length - 1].classList.add('red'); }; } 
+8
javascript html html5 selectors-api
source share
2 answers

The reason is that the querySelectorAll method returns a static list. Any changes made to the document after using querySelectorAll (for example, removeChild in this case) will not be displayed in the list of returned nodes. Therefore, elToStyle[elToStyle.length - 1] still points to the node to be deleted.

Whereas getElementsByClassName , on the other hand, returns a live list of nodes. This means that elToStyle[elToStyle.length - 1] always point to the last .div , regardless of what changes were made to the document after the node list was prepared or not.

Below is an excerpt from the official documentation here

The NodeList returned by querySelectorAll () must be static and not live ([DOM-LEVEL-3-CORE], section 1.1.1). subsequent changes to the structure of the underlying document should not be reflected in the NodeList object. This means that the object will instead contain a list of the corresponding element nodes that were in the document at the time the list was created.

Note: You can see this by running console.log(elToStyle); both before and after removeChild .

+7
source share

If you want to reference the last division element, just do the following ...

 var id = 'container'; var d = document.getElementById(id).getElementsByTagName('div') var lastDiv = d[d.length - 1]; 

.. and then apply your querySelector .

0
source share

All Articles