Here is the code I have right now. Its 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.?
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>