'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