Oreodad
Oreodad

Reputation: 23

Use '.remove()' in a loop to remove the node, why all the nodes won't be removed

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
</head><body>

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

<script>
  let div = document.createElement('div');
  let div1 = document.createElement('div');
  let div2 = document.createElement('div');
  let div3 = document.createElement('div');
  
  div.className = "alert alert-success";
  div1.className = "alert alert-success";
  div2.className = "alert alert-success";
  div3.className = "alert alert-success";
  
  div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
  div1.innerHTML = "<strong>Hi there!1</strong> You've read an important message.";
  div2.innerHTML = "<strong>Hi there!2</strong> You've read an important message.";
  div3.innerHTML = "<strong>Hi there!3</strong> You've read an important message.";
  
  document.body.append(div);
  document.body.append(div1);
  document.body.append(div2);
  document.body.append(div3);
  
  let divs = document.getElementsByTagName('div');
  for(let x of divs){
    x.remove();  
  }
  
</script>

</body>
</html>

I am recently learning the JS, here is a problem I met. I think all the 'div' will be removed, but div1 and div3 are still there.... I don't know why, please help And also explain why this happens? Thanks in advance.

Upvotes: 1

Views: 49

Answers (3)

MaxZoom
MaxZoom

Reputation: 7753

I believe getElementsByTagName returns not array but a live HTML collection.
The collection itself is mutated by the remove() method, which causes unexpected behavior.

The solution: you need to cast it to array before looping

let div = document.createElement('div');
let div1 = document.createElement('div');
let div2 = document.createElement('div');
let div3 = document.createElement('div');

div.className = "alert alert-success";
div1.className = "alert alert-success";
div2.className = "alert alert-success";
div3.className = "alert alert-success";

div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
div1.innerHTML = "<strong>Hi there!1</strong> You've read an important message.";
div2.innerHTML = "<strong>Hi there!2</strong> You've read an important message.";
div3.innerHTML = "<strong>Hi there!3</strong> You've read an important message.";

document.body.append(div);
document.body.append(div1);
document.body.append(div2);
document.body.append(div3);

var divs = document.getElementsByTagName('div');
for(let x of Array.from(divs)) {
  console.log(x.innerHTML);
  x.remove();
}
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}

Upvotes: 3

Andrzej Smyk
Andrzej Smyk

Reputation: 1724

document.getElementsByTagName returns NodeList, not array. NodeList might be iterable object but doesn't have to. To iterate using for ... of construction it is safer to convert NodeList to array using:

  • Array.from
  • spread operator: for (let x of [...divs]) { ... }

 let div = document.createElement('div');
  let div1 = document.createElement('div');
  let div2 = document.createElement('div');
  let div3 = document.createElement('div');
  
  div.className = "alert alert-success";
  div1.className = "alert alert-success";
  div2.className = "alert alert-success";
  div3.className = "alert alert-success";
  
  div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
  div1.innerHTML = "<strong>Hi there!1</strong> You've read an important message.";
  div2.innerHTML = "<strong>Hi there!2</strong> You've read an important message.";
  div3.innerHTML = "<strong>Hi there!3</strong> You've read an important message.";
  
  document.body.append(div);
  document.body.append(div1);
  document.body.append(div2);
  document.body.append(div3);
  
  let divs = document.getElementsByTagName('div');
  for(let x of [...divs]){
    console.log(x.innerHTML);
    x.remove();  
  }
  
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>

<style>
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
</style>

</body>
</html>

Upvotes: 0

Scath
Scath

Reputation: 3824

You need to go through the array of all the divs you got by tag name using the length of the divs array variable you created.

 let div = document.createElement('div');
  let div1 = document.createElement('div');
  let div2 = document.createElement('div');
  let div3 = document.createElement('div');
  
  div.className = "alert alert-success";
  div1.className = "alert alert-success";
  div2.className = "alert alert-success";
  div3.className = "alert alert-success";
  
  div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
  div1.innerHTML = "<strong>Hi there!1</strong> You've read an important message.";
  div2.innerHTML = "<strong>Hi there!2</strong> You've read an important message.";
  div3.innerHTML = "<strong>Hi there!3</strong> You've read an important message.";
  
  document.body.append(div);
  document.body.append(div1);
  document.body.append(div2);
  document.body.append(div3);
  
  let divs = document.getElementsByTagName('div'), x;
  for (x = divs.length - 1; x >= 0; x--) {
    divs[x].parentNode.removeChild(divs[x]);
}
.alert {
  padding: 15px;
  border: 1px solid #d6e9c6;
  border-radius: 4px;
  color: #3c763d;
  background-color: #dff0d8;
}
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
</head><body>
</body>
</html>

Upvotes: 1

Related Questions