views:

457

answers:

5

Hello world,

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.

A: 

You could constantly check if the scroll position changes...

marcgg
That's not a pretty solution, but if you're saying that the events don't trigger immediately...
marcgg
When I say events don't trigger immediately, I mean that in general. If I run those first 3 lines, they all come and go by the time the scroll event is triggered, since that's just how Javascript works.
Matchu
A: 

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
    }
}
Colin
+1  A: 

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() 
{
  var 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 = currentScrollLeft = x;

...

function onScroll() 
{
  // retrieve element, etc... 

  if (element.scrollLeft == currentScrollLeft) return false;

  ...
}
Shog9
In my code, I hit one issue: sometimes it happens that, say, scrollLeft is already 0, then my code also sets it to 0. As such, no scroll event is triggered, and the next user scroll is ignored. (Which is only really an issue if they do scrolling with Home, End, etc.) But this is definitely a close solution - and I knew I was missing something stupid in that dummy implementation. Thanks!
Matchu
I wondered about that... Your best bet then, is to check if you're changing the value before setting the flag - don't set it if you aren't. You might already have this code factored out into a separate function, but if not, then doing so would make that easier - see Rodrigo's answer for an example of this.
Shog9
+1  A: 

¿How about a setter?

var _preventEvent = false;
function setScrollTop(amount) {
  _preventEvent = true;
  window.scrollTop = amount;
}

function setScrollLeft(amount) {
  _preventEvent = true;
  window.scrollLeft = amount;
}

window.onscroll = function () {
  if (_preventEvent) {
    _preventEvent = false;
    return;
  }
}
Rodrigo
A: 

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!

Matchu
so the correct answer is?
Rodrigo
Unsure. What's protocol here? If I use part of an answer then build off it to reach the full answer, do I mark my own or the other?
Matchu