Why function does work different?

Hi, I coded a function that counts from 0 to the value provided by HTML. I also have function that starts the counter when the user scrolls to the section ".advantages". When I call the function "counter()" independently it works fine, but when I call it inside another function, the counting process becomes much faster and I can't prevent that. Can someone explain why does that happen? The commented "counter()" works fine, the "counter()" in the event listener doesn't work how I want it to.
const number = document.querySelectorAll(".number");
const advantages = document.querySelector('.advantages');
const speed = 100;
function counter() {
number.forEach(element => {
incNumber(element);
});
function incNumber(elem) {
let text = +elem.innerText;
const value = +elem.getAttribute("data-count");
const inc = Math.ceil(value / speed);
if(text < value) {
elem.innerText = inc + text;
setTimeout(() => {
incNumber(elem);
}, 20);
} else {
elem.style.marginLeft = "0.5em";
elem.innerText = value;
}
}
}

// counter();


function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)

);
}


document.addEventListener('scroll', function () {
if(isInViewport(advantages)) {
counter();
}

}, {
passive: true
});
const number = document.querySelectorAll(".number");
const advantages = document.querySelector('.advantages');
const speed = 100;
function counter() {
number.forEach(element => {
incNumber(element);
});
function incNumber(elem) {
let text = +elem.innerText;
const value = +elem.getAttribute("data-count");
const inc = Math.ceil(value / speed);
if(text < value) {
elem.innerText = inc + text;
setTimeout(() => {
incNumber(elem);
}, 20);
} else {
elem.style.marginLeft = "0.5em";
elem.innerText = value;
}
}
}

// counter();


function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)

);
}


document.addEventListener('scroll', function () {
if(isInViewport(advantages)) {
counter();
}

}, {
passive: true
});
3 Replies
Chooβ™šπ•‚π•šπ•Ÿπ•˜
The problem is using the scroll event combined with isInViewport(). The element continues to be in viewport as you scroll, so counter() gets called multiple times as more scrolling happens. Also, a single movement of the scroll wheel can register as several scroll events. Using an intersection observer instead will fix this. Alternatively, you can keep track of whether or not the counter has started and not allow it to start again.
Joao
Joaoβ€’17mo ago
Add a console log inside the scroll event callback and see just how often it's being called. The scroll event can be dangerous because of how often is triggered so be, and the intersection observer API will help with situations like this one. Even removing the event listener once your isInViewport function returns true may be unreliable because of the sheer amount of events fired in a very short period of time.
;_;
;_;OPβ€’17mo ago
Ok, I just added the console.log on the event listener and it's triggering the counter() function multiple times. I'll use Intersection Observer. Thanks guys! EDIT I just implemented the Intersection Observer and it works perfectly thumbup
Want results from more Discord servers?
Add your server