Javascript removeChild doesn't work as expected

I have a code that gets characters names and gender after clicking on film name. This information appears in modal window and my goal is to delete HTML element with characters every time I close modal, so if I select another film the new set of characters will appear, and the old one is already deleted.

The problem is that removeChild method doesn't work as expected. I've tried different variations including parentNode but nothing helped.

Here is the code:

window.addEventListener('DOMContentLoaded', function() {
  let btn = document.querySelector('.sw-btn');
  let content = document.querySelector('.content');
  let modal = document.querySelector('.modal');
  let modalBody = document.querySelector('.modal-body');
  let closeBtn = document.querySelector('.close-btn');
  let filmsList = document.createElement('ul');
  let charsList = document.createElement('ol');

  function getFilms() {
    axios.get('https://swapi.co/api/films/').then(res => {
      content.appendChild(filmsList);
      for (var i = 0; i < res.data.results.length; i++) {
        res.data.results.sort(function(a, b) {
          let dateA = new Date(a.release_date),
            dateB = new Date(b.release_date);
          return dateA - dateB;
        });

        (function updateFilms() {
          let addFilm = document.createElement('li');
          filmsList.appendChild(addFilm);

          let addFilmAnchor = document.createElement('a');
          let addFilmId = document.createElement('p');
          let addFilmCrawl = document.createElement('p');
          let addFilmDirector = document.createElement('p');
          let addFilmDate = document.createElement('p');

          addFilmAnchor.textContent = res.data.results[i].title;
          addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
          addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
          addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
          addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;

          addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
        })();
      }
      let links = document.getElementsByTagName('a');
      for (let j = 0; j < links.length; j++) {
        links[j].onclick = function() {
          modal.style.display = 'block';
          modalBody.appendChild(charsList);
          let chars = res.data.results[j].characters;
          for (let k = 0; k < chars.length; k++) {
            const element = chars[k];
            axios.get(element).then(res => {
              let addChar = document.createElement('li');
              charsList.appendChild(addChar);
              let addCharName = document.createElement('p');
              let addCharGender = document.createElement('p');
              addCharName.textContent = `Character name: ${res.data.name}`;
              addCharGender.textContent = `Character gender: ${res.data.gender}`;
              addChar.append(addCharName, addCharGender);
            })
          }
          closeBtn.addEventListener('click', () => {
            modal.style.display = 'none';
            console.log(modalBody.childNodes[0]);
            // Problem is here
            modalBody.removeChild(modalBody.childNodes[0]);
          });
          window.addEventListener('click', (e) => {
            if (e.target == modal) {
              modal.style.display = 'none';
              console.log(modalBody.childNodes[0]);
              modalBody.removeChild(modalBody.childNodes[0]);
            }
          })
        }
      }
    }).catch(err => {
      console.log("An error occured");
    })
  };

  btn.addEventListener('click', getFilms);

  closeBtn.addEventListener('click', () => {
    modal.style.display = 'none';
  });
  window.addEventListener('click', (e) => {
    if (e.target == modal) {
      modal.style.display = 'none';
    }
  })
});
body {
  max-height: 100vh;
  padding: 0;
  margin: 0;
  font-family: Muli;
}

body::before {
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
  background-size: cover;
  content: "";
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  opacity: 0.1;
}

h1 {
  text-align: center;
  color: #660d41;
  font-size: 3em;
  margin-top: 10px;
  letter-spacing: 1px;
}

main {
  display: flex;
  align-items: center;
  flex-direction: column;
}

.content {
  max-width: 55%;
  overflow-y: scroll;
  max-height: 75vh;
}

.modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgba(0, 0, 0, 0.5);
}

.modal-content {
  background-color: #f4f4f4;
  margin: 20% auto;
  width: 40%;
  box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
  animation: modalOpen 1s;
}

.modal-header {
  background: coral;
  padding: 15px;
  color: white;
  letter-spacing: 1px;
  position: relative;
}

.modal-header h2 {
  margin: 0;
}

.modal-body {
  padding: 10px 20px;
}

.close-btn {
  color: white;
  float: right;
  font-size: 30px;
  position: absolute;
  top: 0px;
  right: 10px;
}

.close-btn:hover,
.close-btn:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.4s ease-in;
}

ul {
  list-style-type: none;
  padding: 10px 20px;
}

li {
  border-bottom: 1px solid orangered;
  margin-bottom: 30px;
}

li:last-child {
  border-bottom: none;
  margin-bottom: 0;
}

a {
  font-size: 1.7em;
  color: #b907d9;
  cursor: pointer;
  margin-bottom: 10px;
}

p {
  font-size: 1.2rem;
  color: #0f063f;
  margin: 10px 0;
}

button {
  padding: .5em 1.5em;
  border: none;
  color: white;
  transition: all 0.2s ease-in;
  background: #da2417;
  border-radius: 20px;
  font-size: 1em;
  cursor: pointer;
  margin-top: 15px;
}

button:focus {
  outline: none;
}

button:hover {
  background: #e7736b;
}

button:active {
  box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}

@keyframes modalOpen {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
  <div class="content"></div>
  <div class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <span class="close-btn">&times;</span>
        <h2>Episode Characters</h2>
      </div>
      <div class="modal-body"></div>
    </div>
  </div>
  <button class="sw-btn">Find Films</button>
</main>

Any help would be appreciated.

Upvotes: 2

Views: 130

Answers (2)

yip102011
yip102011

Reputation: 877

Do this charsList.innerText = ''; when click close button.

When you call removeChild you take off the <ol> from modalbody in UI. You can see the modalBody is empty after clicking close button.

But you already store the <ol> element in js variable by let charsList = document.createElement('ol'); so the ol element itself doesn't change actually. The <li> element still inside the <ol>. Then you add more new <li> and put it back to modalBody.

enter image description here

My solution is remove all element in <ol> when clicking close button.

Upvotes: 0

Carsten
Carsten

Reputation: 943

The problem is that you are using the same ol element when appending the characters to the list, since you instantiate it at the beginning and re-use it later: let charsList = document.createElement('ol');

When you close the modal, you will remove that ol element from the modal, but you will not remove its content. When opening the modal again, the ol will be added again - with your old content.

If you move the declaration of charsList inside your onclick handler, it will work.

Also, you should register the close handlers of your modal only once. Otherwise, it will be called as often as you open your modal.

Demo:

window.addEventListener('DOMContentLoaded', function () {
    let btn = document.querySelector('.sw-btn');
    let content = document.querySelector('.content');
    let modal = document.querySelector('.modal');
    let modalBody = document.querySelector('.modal-body');
    let closeBtn = document.querySelector('.close-btn');
    let filmsList = document.createElement('ul');

    closeBtn.addEventListener('click', () => {
        modal.style.display = 'none';
        console.log(modalBody.childNodes[0]);
        modalBody.removeChild(modalBody.childNodes[0]);
    });
    
    window.addEventListener('click', (e) => {
        if (e.target == modal) {
            modal.style.display = 'none';
            console.log(modalBody.childNodes[0]);
            modalBody.removeChild(modalBody.childNodes[0]);
        }
    })

    function getFilms() {
        axios.get('https://swapi.co/api/films/').then(res => {
            content.appendChild(filmsList);
            for (var i = 0; i < res.data.results.length; i++) {
                res.data.results.sort(function (a, b) {
                    let dateA = new Date(a.release_date),
                        dateB = new Date(b.release_date);
                    return dateA - dateB;
                });

                (function updateFilms() {
                    let addFilm = document.createElement('li');
                    filmsList.appendChild(addFilm);

                    let addFilmAnchor = document.createElement('a');
                    let addFilmId = document.createElement('p');
                    let addFilmCrawl = document.createElement('p');
                    let addFilmDirector = document.createElement('p');
                    let addFilmDate = document.createElement('p');

                    addFilmAnchor.textContent = res.data.results[i].title;
                    addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
                    addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
                    addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
                    addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;

                    addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
                })();
            }
            let links = document.getElementsByTagName('a');
            for (let j = 0; j < links.length; j++) {
                links[j].onclick = function () {
                    modal.style.display = 'block';
                    let charsList = document.createElement('ol');
                    modalBody.appendChild(charsList);
                    let chars = res.data.results[j].characters;
                    for (let k = 0; k < chars.length; k++) {
                        const element = chars[k];
                        axios.get(element).then(res => {
                            let addChar = document.createElement('li');
                            charsList.appendChild(addChar);
                            let addCharName = document.createElement('p');
                            let addCharGender = document.createElement('p');
                            addCharName.textContent = `Character name: ${res.data.name}`;
                            addCharGender.textContent = `Character gender: ${res.data.gender}`;
                            addChar.append(addCharName, addCharGender);
                        })
                    }
                }
            }
        }).catch(err => {
            console.log("An error occured");
        })
    };

    btn.addEventListener('click', getFilms);

    closeBtn.addEventListener('click', () => {
        modal.style.display = 'none';
    });
    window.addEventListener('click', (e) => {
        if (e.target == modal) {
            modal.style.display = 'none';
        }
    })
});
body {
  max-height: 100vh;
  padding: 0;
  margin: 0;
  font-family: Muli;
}

body::before {
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
  background-size: cover;
  content: "";
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  opacity: 0.1;
}

h1 {
  text-align: center;
  color: #660d41;
  font-size: 3em;
  margin-top: 10px;
  letter-spacing: 1px;
}

main {
  display: flex;
  align-items: center;
  flex-direction: column;
}

.content {
  max-width: 55%;
  overflow-y: scroll;
  max-height: 75vh;
}

.modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgba(0, 0, 0, 0.5);
}

.modal-content {
  background-color: #f4f4f4;
  margin: 20% auto;
  width: 40%;
  box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.2);
  animation: modalOpen 1s;
}

.modal-header {
  background: coral;
  padding: 15px;
  color: white;
  letter-spacing: 1px;
  position: relative;
}

.modal-header h2 {
  margin: 0;
}

.modal-body {
  padding: 10px 20px;
}

.close-btn {
  color: white;
  float: right;
  font-size: 30px;
  position: absolute;
  top: 0px;
  right: 10px;
}

.close-btn:hover,
.close-btn:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.4s ease-in;
}

ul {
  list-style-type: none;
  padding: 10px 20px;
}

li {
  border-bottom: 1px solid orangered;
  margin-bottom: 30px;
}

li:last-child {
  border-bottom: none;
  margin-bottom: 0;
}

a {
  font-size: 1.7em;
  color: #b907d9;
  cursor: pointer;
  margin-bottom: 10px;
}

p {
  font-size: 1.2rem;
  color: #0f063f;
  margin: 10px 0;
}

button {
  padding: .5em 1.5em;
  border: none;
  color: white;
  transition: all 0.2s ease-in;
  background: #da2417;
  border-radius: 20px;
  font-size: 1em;
  cursor: pointer;
  margin-top: 15px;
}

button:focus {
  outline: none;
}

button:hover {
  background: #e7736b;
}

button:active {
  box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}

@keyframes modalOpen {
  from {
    opacity: 0
  }
  to {
    opacity: 1
  }
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<h1>Star wars films</h1>
<main>
  <div class="content"></div>
  <div class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <span class="close-btn">&times;</span>
        <h2>Episode Characters</h2>
      </div>
      <div class="modal-body"></div>
    </div>
  </div>
  <button class="sw-btn">Find Films</button>
</main>

Upvotes: 3

Related Questions