Sometimes I think I'm a Stack Overflow junky π€ͺ... And my addiction was worse a few months ago when I saw this question and couldn't resist my fingers from tackling it.
The main idea was to..
π οΈ Build a JavaScript algorithm that would make counters start at different speeds depending on the value set in the speed attribute of the HTML span tag elements. 
I feel that is an interesting and fun code to share with others.
If you want to try out the snippet π click here
Before you continue..
I've written this post in great detail so that it can be understood by begginers. The idea of the post is to have fun programming, learn/practice a few things, experiment and maybe come up with a different or even a better solution that the one I came up with.
If(you_want_to_continue === true) console.log('keep scrolling..')
else console.log('see you! π') 
Grab some β and lets get started!
Go to your favorite JS code editor (JSFiddle is pretty cool) and setup the HTML
<h1 class="counter" speed='3'></h1>
<h1 class="counter" speed='7'></h1>
<h1 class="counter" speed='10'></h1>
<h1 class="counter" speed='12'></h1>
As you can see, I added the speed attribute to the h1 elements. The class counter is to let JS know which elements we want to select using the querySelectorAll()
Now that the HTML code is ready is time to start programming
Let's declare the elements const
const elements = document.querySelectorAll('.counter')
π¬ For those who don't know, the document method querySelectorAll() returns a static NodeList representing a list of the document's elements that match the specified group of selectors. 
π§ So, in this case elements will contain all h1 elements that have the class counter.
console.log(elements) outputs:
{
  "0": <h3 class="counter" speed="6"></h3>,
  "1": <h3 class="counter" speed="7"></h3>,
  "2": <h3 class="counter" speed="8"></h3>,
  "3": <h3 class="counter" speed="9"></h3>,
  "item": function item() {
    [native code]
},
  "keys": function keys() {
    [native code]
},
  "values": function values() {
    [native code]
},
  "entries": function entries() {
    [native code]
},
  "forEach": function forEach() {
    [native code]
},
  "length": 4
}
This doesn't look very nice, I know.. But accessing the elements is simple.
They can be accessed by their ποΈ key: elements[key]. For example elements['1'] returns the following HTML element:
<h3 class="counter" speed="7"></h3>
Now that we understand how to retrieve and work with the static NodeList elements let's start to build the logic by creating a function that will set intervals for every HTML element in elements.
function setCounter(element, speed, limit){
  let count = 0  // every count will start from 0
  let interval = setInterval(() => {
    // in every interval the count will increment by the speed value 
    count += speed
    // update the HTML in this specific element  
    element.innerHTML = count
    // stop the setInterval() if condition is met
    if(count >= limit) clearInterval(interval)
  }, 1) // <--- the interval will loop every 1 millisecond
}
Now that the setCounter() function is ready we need to loop through all the elements to retrieve their speed, and invoke the setCounters() but before doing that, we need to be clear on how to get and use all speeds.
To retrieve the speed we need to specify from which element are we going to get the attribute from:
elements[key].getAttribute('speed') 
π¬ When using .getAttribute() the returned value comes as a string. This can be prooven by using typeof like so:
let key = '1'
let value = elements[key].getAttribute('speed')
console.log(typeof value) // --> string
To make the code work, we need to convert to integer by using Number() or parseInt().
After this we have all needed to invoke setCounter(element, speed, limit). This will initialize each setInterval with their respective parameters.
elements.forEach((el, key) => {
  let speed = Number(elements[key].getAttribute('speed'))
  setCounter(el, speed, 1000) 
})
Now that the code is completed do you think is going to work properly ?
Let's give it a shot and see what happens. Take into consideration that the limit passed as a parameter to setCounter() is 1000
It didn't work properly π... The setIntervals are working but they are showing a bigger count than the limit. This is because the value of the speed that is added to the count is not summing 1 in every loop, it can be any number so it can overflow the limit. 
One way of solving this, is by using a ternary operator inside the setInterval(), like so:
count = (count >= limit) ? limit : count + speed
How does this work?
If count is bigger or equal to limit, count will equal to limit and in the opposite case count will equal count + speed.
This is a minor patch to solve the last loop count problem. By doing this the count will never overflow the limit.
The resulting code βοΈ
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)
}
This is my first post in dev.to
Feel free to experiment/play with the code and share your unique approach π if you have one π
 
 
              

 
    
Top comments (0)