I have an element that is scrollable. I also have a function that scrolls to a specific position. I would like to call a function when the scrollTo is finished.
Plunkr example
var x = document.querySelector('.container');
$scope.scrollTo = function() {
x.scrollTo({
top: 300 ,
behavior: 'smooth'
});
};
// do something when scrollTo is finished
By checking the position of the element I am scrolling to and comparing that to the current scroll position of the container you can see when the scrolling action is finished.
function isScrollToFinished() {
const checkIfScrollToIsFinished = setInterval(() => {
if (positionOfItem === scrollContainer.scrollTop) {
// do something
clearInterval(checkIfScrollToIsFinished);
}
}, 25);
}
The interval checks if the position of the scroll container is equal to the position of the element I'm scrolling to. Then do a action and clear the interval.
I suggest checking that the scroll movement is gone.
Less parameter, no risk, and works for extremes positions.
let position = null
const checkIfScrollIsStatic = setInterval(() => {
if (position === window.scrollY) {
clearInterval(checkIfScrollIsStatic)
// do something
}
position = window.scrollY
}, 50)
I modified @DoiDor's answer to ensure that the position is rounded and include a timeout fallback just in case. Otherwise the position may never be reached exactly, and the promise would never resolve.
async function scrollToPosition(container, position) {
position = Math.round(position);
if (container.scrollTop === position) {
return;
}
let resolveFn;
let scrollListener;
let timeoutId;
const promise = new Promise(resolve => {
resolveFn = resolve;
});
const finished = () => {
container.removeEventListener('scroll', scrollListener);
resolveFn();
};
scrollListener = () => {
clearTimeout(timeoutId);
// scroll is finished when either the position has been reached, or 100ms have elapsed since the last scroll event
if (container.scrollTop === position) {
finished();
} else {
timeoutId = setTimeout(finished, 100);
}
};
container.addEventListener('scroll', scrollListener);
container.scrollTo({
top: position,
behavior: 'smooth',
});
return promise;
}
I'm using a solution similar to this:
function scrollElementTo(el, position) {
return new Promise((resolve) => {
const scrollListener = (evt) => {
if (typeof evt === 'undefined') {
return;
}
const target = evt.currentTarget;
if (target.scrollTop === position) {
target.removeEventListener('scroll', scrollListener);
resolve();
}
};
el.addEventListener('scroll', scrollListener);
// scroll to desired position (NB: this implementation works for
// vertical scroll, but can easily be adjusted to horizontal
// scroll as well)
el.scrollTo(0, position);
});
}
const scrollContainer = document.querySelector('#theScrollContainer');
// desired y coords for scroll
const yDesiredScroll = 234;
scrollElementTo(scrollContainer, yDesiredScroll).then(() => {
// do something here
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With