Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do I get the "can't read properties of null" error, when using "querySelectorAll.forEach"?

Here is the code I have right now. It’s purpose is to place an event listener on every button with the same class using querySelectorAll and some loop (currently using forEach), and make it a togglable "fav", toggling which will add or subtract 1 from the text in the span inside the button:

const likeButtonArray = document.querySelectorAll('.likeButton');
const likeCountArray = document.querySelectorAll('.likeCount');
let likeButton = Array.from(likeButtonArray);
let likeCount = Array.from(likeCountArray);
// let count;
// [...likeButton].forEach((node) => console.log(node));
likeButton.forEach((like,index) => {
  /* Uncaught TypeError: Cannot read properties of null
  at NodeList.forEach (<anonymous>), at scr.js:3:12 */
  let count = parseInt(document.querySelector(`#likeCount:nth-of-type(${index+1})`).innerHTML);
  // let count = parseInt(document.querySelector(`like.firstElementChild`).innerHTML);
  // Uncaught TypeError: Cannot read properties of null (reading 'innerHTML' at scr.js:4:84
  console.log(`assigned: ${index+1} ~ ${count}`)
  let counter = false;
  like.addEventListener('click', () => {
    counter = !counter;
    if(counter) {
      console.log(`added for   ${index}`);
      count++;
      // like.classList.add('active');
      likeCount[index].innerHTML = toString(parseInt(like.innerHTML) + 1);
    } else {
      console.log(`removed for ${index}`);
      count--;
      // like.classList.remove('active');
      likeCount[index].innerHTML = toString(parseInt(like.innerHTML) - 1);
    }
    like.classList.toggle('active');
    console.log(`clicked:    ${index+1} ~ ${count}`)
    // likeCount[index].textContent = count.toString();
  });
});
* {
  border: 0;
  outline: 0;
  box-sizing: border-box;
}
.likeButton {
  background: black;
  color: white;
}
.likeButton.active {
  border: 1px dashed blue;
  background: white;
  color: black;
}
<div class="wrap">
  <button class="likeButton">
  <span class="likeCount">69</span></button>
</div>
<div class="wrap">
  <button class="likeButton">
  <span class="likeCount">420</span></button>
</div>

I had the span outside of the button earlier, but it has to be inside of it, so some JS is still leftover from the before. But, the code errors stayed the same:

scr.js:5 Uncaught TypeError: Cannot read properties of null (reading 'innerHTML')
    at scr.js:5:84
    at NodeList.forEach (<anonymous>)
    at scr.js:3:12

The code is not working, at all. Here is what is happening:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The first button is the only one which has an event listener, all others do nothing when clicked.

It’s inner HTML is changed to "[objectUndefined]", and the class gets toggled.

I also get all the console logs that I placed.

EDIT: I decided to convert nodeLists to arrays by adding lines 3 and 4, and now nothing is working.

Why? How can I fix this, while keeping my code D.R.Y.?

>Solution :

You are really over complicating things. Select the buttons. Add a click listener to the button. Toggle the class. Select the element in the button that has the count and update the count based on the selection.

const likeButtonArray = document.querySelectorAll('.likeButton');

likeButtonArray.forEach(button => {

  // add the click event to the button
  button.addEventListener("click", e => {

    // toggle the class
    button.classList.toggle("active");

    // Determine if active or not to do the calculation
    const dir = button.classList.contains("active") ? 1 : -1;

    // find the count holder in the button
    const countElem = button.querySelector(".likeCount");

    // update the count
    const likes = +countElem.textContent + dir;
    countElem.textContent = likes;
  });

});
* {
  border: 0;
  outline: 0;
  box-sizing: border-box;
}
.likeButton {
  background: black;
  color: white;
}
.likeButton.active {
  border: 1px dashed blue;
  background: white;
  color: black;
}
<div class="wrap">
  <button class="likeButton">
  <span class="likeCount">69</span></button>
</div>
<div class="wrap">
  <button class="likeButton">
  <span class="likeCount">420</span></button>
</div>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading