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:
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.?
2
Answers
Simply use a regular old
for
loop asdocument.querySelectorAll()
returns a node-list andforEach
may not be supported on all browsers for node-list. SincelikeCount
will have the same index aslikeButton
, I have replaced the code for getting count bylet count = parseInt(likeCount[index].innerHTML);
. You also, don’t need to usetoString
asinnerHTML
can take number and will parse automatically. the code is cleaner and more readable now.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.