1

I'd like to execute a function that iterates over the child nodes of an element and subsequently deletes each child node.

In my current setup, for some reason, only some of the child nodes get deleted, some don't. The function needs to run multiple times to delete all nodes. Why aren't all nodes deleted at once?

Here's a simplified version of the code:

const deleteBtn = document.getElementById("deleteBtn");
const sidebar = document.getElementById("sidebar");

deleteBtn.addEventListener("click", () => {
  const links = sidebar.children;
  console.log(links)

  for (let i = 0; i < links.length; i++) {
    const link = links[i];
    link.remove()
  }
})
.sidebar__link-group {
  display: flex;
  flex-direction: column;
}
<button id="deleteBtn" >Click to delete all links</button>

<div id="sidebar" class="sidebar__link-group">
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
</div>
JoSch
  • 869
  • 1
  • 15
  • 35

3 Answers3

4

When you remove the 0th element, the 1st element becomes the 0th, the 2nd element becomes the 1st, etc, so after your first i++, you're gonna delete the "original 2nd" element, and so on; that is why your algorithm only removes every other children instead of every children.

That's typically the kind of algorithm where you'd want to use a while instead of an array iteration:

const deleteBtn = document.getElementById("deleteBtn");
const sidebar = document.getElementById("sidebar");

deleteBtn.addEventListener("click", () => {
  while(sidebar.children.length > 0) {
    sidebar.children[0].remove();
  }
  console.log('done');
})
.sidebar__link-group {
  display: flex;
  flex-direction: column;
}
<button id="deleteBtn" >Click to delete all links</button>

<div id="sidebar" class="sidebar__link-group">
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
</div>
Nino Filiu
  • 16,660
  • 11
  • 54
  • 84
0

As Pablo said, I think the issue might be that you're removing items from the very list you're iterating over (although if that were the issue, I would expect to see more links left over, so I'm not sure...)

Anyway, I thought that iterating in reverse over the list and removing them like that might solve the issue, so how about this?:

const deleteBtn = document.getElementById("deleteBtn");
const sidebar = document.getElementById("sidebar");

deleteBtn.addEventListener("click", () => {
  const links = sidebar.children;
  console.log(links)

  for (let i = links.length - 1; i >= 0; i--) {
    const link = links[i];
    link.remove()
  }
})
.sidebar__link-group {
  display: flex;
  flex-direction: column;
}
<button id="deleteBtn" >Click to delete all links</button>

<div id="sidebar" class="sidebar__link-group">
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
</div>

[edit]

With some testing, I'm pretty sure Pablo is right -- when you do something like x = document.getElementById('someid').children, and then you do something like x[1].remove(), the actual array x now has a length of 1 less than it did at the start. That's why iterating over it backwards works.

TKoL
  • 13,158
  • 3
  • 39
  • 73
0

You could do this:

const deleteBtn = document.getElementById("deleteBtn");
const sidebar = document.getElementById("sidebar");

deleteBtn.addEventListener("click", () => {
  while(sidebar.firstChild) {
    sidebar.children[0].remove();
  }
  console.log('done');
})
.sidebar__link-group {
  display: flex;
  flex-direction: column;
}
<button id="deleteBtn" >Click to delete all links</button>

<div id="sidebar" class="sidebar__link-group">
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
</div>

In case you don't need to check anything before deleting, you could also try this:

const deleteBtn = document.getElementById("deleteBtn");
const sidebar = document.getElementById("sidebar");

deleteBtn.addEventListener("click", () => {
  sidebar.innerHTML="";
  console.log('done');
})
.sidebar__link-group {
  display: flex;
  flex-direction: column;
}
<button id="deleteBtn" >Click to delete all links</button>

<div id="sidebar" class="sidebar__link-group">
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
  <a class="sidebar__link" href="#">Some link</a>
</div>
Aditya Menon
  • 744
  • 5
  • 13