简体   繁体   中英

append / appendChild not working on all items

I'm trying to move all the list items from an list to another using only javascript but for some reason only half of them are actually moved.

Heres a working example of what I'm doing:

 var results_ul = document.getElementById('results'); var stores_li = document.getElementsByClassName('store-list-item'); for (var x = 0; x < stores_li.length; x++) { document.getElementById('hide').appendChild(stores_li[x]); stores_li[x].className += ' teste'; } 
 <p>results</p> <ul id="results"> <li class="store-list-item">Teste 1</li> <li class="store-list-item">Teste 2</li> <li class="store-list-item">Teste 3</li> <li class="store-list-item">Teste 4</li> </ul> <p>Hide:</p> <ul id="hide"></ul> 

What seems to be the problem?

getElementsByClassName returns a live list.

When you append the element to a different element, you change its position in the list.

So it starts off as:

1 2 3 4

Then you move the first one:

2 3 4 1

Then you access the second one … but the second one is now 3 because everything has shuffled down the list.


You could copy each element into an array (which will not be a live list) and then iterate over that array to move them (so they won't change positions as you go).

Alternatively, you could use querySelectorAll which returns a non-live list.

You should better use querySelectorAll than getElementsByClassName

 var results_ul = document.getElementById('results'); var stores_li = document.querySelectorAll('.store-list-item'); stores_li.forEach((item)=>{ document.getElementById('hide').appendChild(item); item.className += ' teste'; }); 
 <p>results</p> <ul id="results"> <li class="store-list-item">Teste 1</li> <li class="store-list-item">Teste 2</li> <li class="store-list-item">Teste 3</li> <li class="store-list-item">Teste 4</li> </ul> <p>Hide:</p> <ul id="hide"></ul> 

Try use querySelectorAll . It'll returns a non-live list. That's what you need.

var stores_li = document.querySelectorAll('.store-list-item');

To increase more information:

Live : when the changes in the DOM are reflected in the collection. The content suffers the change when a node is modified.

Non-Live : when any change in the DOM does not affect the content of the collection.

document.getElementsByClassName() is an HTMLCollection, and is live.

document.querySelectorAll() is a NodeList and is not live.

In your code you are removing each element from the first list and inserting into the new list. After you remove 2 elements it will have only 2 elements in the first list but now you are searching the 3 rd index in the loop which is not there. So to make it work i have prepended each element from the last.

 var results_ul = document.getElementById('results'); var stores_li = document.getElementsByClassName('store-list-item'); var hide_ul = document.getElementById('hide'); for (var x = 0, y = stores_li.length; x < y; x++) { hide_ul.insertBefore(stores_li[yx-1],hide_ul.firstChild); stores_li[x].className += ' teste'; } 
 <p>results</p> <ul id="results"> <li class="store-list-item">Teste 1</li> <li class="store-list-item">Teste 2</li> <li class="store-list-item">Teste 3</li> <li class="store-list-item">Teste 4</li> </ul> <p>Hide:</p> <ul id="hide"></ul> 

Or you may want to clone the element with Jquery and you can push into the clonned ones then delete the orginals from top. I could not find any equivalent of clone() for js but if you want to check link is here

var results_ul = document.getElementById('results');
var stores_li = document.getElementsByClassName('store-list-item');

while(stores_li.length>0) {
   document.getElementById('hide').appendChild(stores_li[0]);
   stores_li[x].className += ' teste';
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM