0

I have several list elements on my page that are created dynamically, and my goal now is to access all the <li> on my page using getElementsByTagName, but when I try to do it, console tells me that the length of my li array is 0.

I've read documentation and examples on getElementsByTagName use cases but didn't track the problem.

Here is my code:

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

  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);
        })();
      }
    }).catch(err => {
      console.log("An error occured");
    })

    let links = document.getElementsByTagName('li');
    console.log(links.length);
  };

  btn.addEventListener('click', getFilms);
});
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;
}

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;
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<h1>Star wars films</h1>
<main>
  <div class="content"></div>
  <button class="sw-btn">Find Films</button>
</main>

Here is the link on working pen. Thank you for your help.

connexo
  • 53,704
  • 14
  • 91
  • 128

2 Answers2

2

So what's happening here is a classic mistake caused by an async ajax request. You are requesting data and then inserting elements based on that data. Then afterwards, you want to count elements.

The problem is though, that axios.get returns a Promise that will not immediately resolve, because a HTTP request is being made to another server. That obviously takes some time, hence the then method of the Promise interface.

What you want to do is move your counting code at the end of the .then() method, so that the elements are counted after they have been inserted.

tl;dr you are trying to count elements that simply aren't there at the time of the counting.

buffy
  • 536
  • 2
  • 11
1

That's because length is outside of then. That means you are logging length of empty html collection at the first rendering of the page.

put it inside of then and then it will show correct value

like this:

addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
let links = document.getElementsByTagName('li');
console.log(links.length);
McAwesome
  • 286
  • 3
  • 13