Alex Rivera | Logout

Make "scrollLeft" / "scrollTop" changes not trigger scroll event listener

Asked 2009-09-06T20:51:41.330
37

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.

Edit
Report

3 Answers

32

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;
  }

  ...
}
answered 2009-09-06T21:19:55.127
10

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>

answered 2009-09-06T21:21:27.900
0

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!

answered 2009-09-06T21:53:15.683

Your Answer