javascript element.remove() not remove dom

Issue

element.remove() seem to weird.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script>
    class View {
      constructor() {
        this.parent = document.querySelector('#root')
      }
      template() {
        return `
        <div>Random Num</div>
        <div>${Math.random()}</div>
        <button type='button'>Reset Random Num</button>
      `
      }
      render() {
        const templateElement = document.createElement('template')
        templateElement.innerHTML = this.template()
        templateElement.content
          .querySelector('button')
          .addEventListener('click', () => {
            this.rerender()
          })
        this.parent.append(templateElement.content)
      }
      rerender() {
        this.parent.childNodes.forEach((item) => {
          // here is the problem
          item.remove()
        })
        // const templateElement = document.createElement('template')
        // templateElement.innerHTML = this.template()
        // this.parent.append(templateElement.content)
      }
    }
    const viewIns = new View()
    viewIns.render()
  </script>
</html>

when I click the button, doms don’t get removed at all,and then I clicked the button again ,only the div contains the random number left,I’m really confused why is that.

Solution

childNodes returns a live collection. Live collections can be unintuitive to work with, because they can mutate themselves while you’re iterating over them and throw you off. Here, you’re .remove()ing a text node, and then the <div>Random Num</div> instantly becomes the 0th index in the collection. Then you move on to the 1st index in the collection, which is another text node. The process repeats a few times, removing all text nodes, but not removing any elements.

Turn the childNodes into an array first, so that the collection won’t change while you’re iterating over it.

[...this.parent.childNodes].forEach((item) => {
class View {
  constructor() {
    this.parent = document.querySelector('#root')
  }
  template() {
    return `
        <div>Random Num</div>
        <div>${Math.random()}</div>
        <button type='button'>Reset Random Num</button>
      `
  }
  render() {
    const templateElement = document.createElement('template')
    templateElement.innerHTML = this.template()
    templateElement.content
      .querySelector('button')
      .addEventListener('click', () => {
        this.rerender()
      })
    this.parent.append(templateElement.content)
  }
  rerender() {
    [...this.parent.childNodes].forEach((item) => {
      item.remove()
    })
    // const templateElement = document.createElement('template')
    // templateElement.innerHTML = this.template()
    // this.parent.append(templateElement.content)
  }
}
const viewIns = new View()
viewIns.render()
<div id="root"></div>

Or, an easier approach would be to just set the .innerHTML of the parent to the empty string.

this.parent.innerHTML = '';

Answered By – CertainPerformance

Answer Checked By – David Goodson (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.