'Simple counters - dataset not working properly
I am working on a site that has a lot of counters and I have a problem getting the [data-speed] to create different counter speeds depending on the number in that counter.
When I run this forEach loop I always get the same speed, the function gets the largest number from all the counters.
Any idea where I went wrong?
const counters = document.querySelectorAll('.counter');
let i = 0;
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
const finalNumber = entry.target.innerText;
const speed = +entry.target.dataset.speed;
if (entry.isIntersecting) {
entry.target.innerText = i;
const interval = setInterval(() => {
entry.target.innerText = i += speed;
if (i >= finalNumber) {
entry.target.innerText = finalNumber;
clearInterval(interval);
}
}, 10)
}
})
})
counters.forEach(item => io.observe(item))
<h1 class="counter" data-speed="1">1000</h1>
<h1 class="counter" data-speed="2">1000</h1>
<h1 class="counter" data-speed="3">1000</h1>
<h1 class="counter" data-speed="4">1000</h1>
<h1 class="counter" data-speed="5">1000</h1>
Solution 1:[1]
You have declared the i
globally. So all the entries will share same innerText, since i
is being operated on globally. To fix this, you need to declare the i
variable for each entry, inside the entries.forEach
. This will make sure, each entry has its own 'i'
locally, and operate on it accordingly.
const counters = document.querySelectorAll('.counter');
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
let i = 0;
const finalNumber = entry.target.innerText;
const speed = +entry.target.dataset.speed;
if (entry.isIntersecting) {
entry.target.innerText = i;
const interval = setInterval(() => {
i = i + speed;
entry.target.innerText = i;
if (i >= finalNumber) {
entry.target.innerText = finalNumber;
clearInterval(interval);
}
}, 10)
}
})
})
counters.forEach(item => io.observe(item))
<h1 class="counter" data-speed="1">1000</h1>
<h1 class="counter" data-speed="2">1000</h1>
<h1 class="counter" data-speed="3">1000</h1>
<h1 class="counter" data-speed="4">1000</h1>
<h1 class="counter" data-speed="5">1000</h1>
Solution 2:[2]
I don't know how to help you with your code, but I programmed an alternative way of achieving this that may be of use.
const elements = document.querySelectorAll('.counter')
elements.forEach((el, key) => {
let speed = Number(elements[key].getAttribute('speed'))
setCounter(el, speed, 1000)
})
function setCounter(element, speed, limit){
let count = 0
let interval = setInterval(() => {
count = (count >= limit) ? limit : count + speed
if(count === limit) clearInterval(interval)
element.innerHTML = count
}, 1)
}
<h3 class="counter" speed='6'></h1>
<h3 class="counter" speed='7'></h1>
<h3 class="counter" speed='8'></h1>
<h3 class="counter" speed='9'></h1>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | TechySharnav |
Solution 2 |