Reputation: 85794
Currently my program is in a spot where it both listens for the user to scroll a certain element, but also, at times, automatically scrolls this element by itself. (Not a gradual, pretty scroll, but an instant jump. It makes sense in context, I swear.)
Is there a way to make the scroll event not trigger if the scrolling was done by setting scrollLeft or scrollTop? My first thought was a basic switch, like:
ignoreScrollEvents = true;
element.scrollLeft = x;
ignoreScrollEvents = false;
function onScroll() {
if(ignoreScrollEvents) return false;
}
but since events don't trigger immediately (oops, duhh), that's not a workable solution. What other sort of answers could I try? I'm also using jQuery, if that helps anything.
Upvotes: 35
Views: 41861
Reputation: 159618
Easiest generic method? Just reset the flag in the event handler. You'll want to check first if you're actually changing the value, as otherwise an event won't be fired - as Rodrigo notes, a good practice here is to factor this out into so-called "setter" functions:
function setScrollLeft(x) {
if (element.scrollLeft != x) {
ignoreScrollEvents = true;
element.scrollLeft = x;
}
}
...
function onScroll() {
const ignore = ignoreScrollEvents;
ignoreScrollEvents = false;
if (ignore) {
return false;
}
...
}
But, depending on your needs, you may already be storing the scroll position somewhere; if so, just update and check that as your flag. Something like:
element.scrollLeft = x;
currentScrollLeft = x;
...
function onScroll() {
// retrieve element, etc...
if (element.scrollLeft == currentScrollLeft) {
return false;
}
...
}
Upvotes: 31
Reputation: 4395
How about a setter?
var _preventEvent = false; // set global flag
function setScrollTop(amount) {
_preventEvent = true; // set flag
document.documentElement.scrollTop = amount * Math.random();
}
function setScrollLeft(amount) {
_preventEvent = true; // set flag
document.documentElement.scrollLeft = amount * Math.random();
}
// scroll event listener
window.onscroll = function() {
console.clear();
if (_preventEvent) {
_preventEvent = false; // reset flag
return;
}
console.log('normal scroll');
}
html{ height:500%; width:500%; }
button{ position:fixed; }
button + button{ top:50px; }
<button onclick=setScrollTop(1000)>Random scrollTop</button>
<button onclick=setScrollLeft(1000)>Random scrollLeft</button>
Upvotes: 10
Reputation: 85794
All right, my final solution, building off of Shog9 (not my real code, but my approach):
var oldScrollLeft = element.scrollLeft;
element.scrollLeft = x;
if(element.scrollLeft != oldScrollLeft) {
ignoreScrollEvents = true;
}
function onScroll() {
if(!ignoreScrollEvents) performGreatActions();
ignoreScrollEvents = false;
}
The if statement only sets the ignore flag when the scrollLeft value actually ends up changing, so cases like setting from 0 to 0 don't set the flag incorrectly.
Thanks, all!
Upvotes: 0
Reputation: 2502
You could try storing the offset top of your element and matching it against the scrollTop when you step inside onScroll:
function onScroll(){
var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop),
offsetTop = $('selector').offset().top;
if(offsetTop > scrollTop){
//user has not scrolled to element so do auto scrolling
}
}
Upvotes: 0