1

I'm trying to get a javascript function to run only once. I've seen this question has been asked before, e.g. Function in javascript that can be called only once, but I can't get the solutions in here to work. I'm not sure if it's because I've got nested functions, or whether there's something I'm missing. Essentially, I'm trying to run a function which, when a webpage is scrolled, it: - runs a little animation on a canvas in the header - reduces the size of the header - leaves it at that

But when there is any subsequent scrolling, the animation keeps re-running. Here's a summarised version of the non-working code:

$(document).on("scroll",function(){

    var arrange_title = function(){

        //some code 
    };

    if($(document).scrollTop()>0){ 
        arrange_title();
        arrange_title = function(){};
        setTimeout(function(){
            $("header").removeClass("large").addClass("small");
        },1000);
    }
});

I've also tried declaring a global variable, setting it to "false" in a "window.onload" function, then set it to true in an if function that runs the animation (the if function running only if the variable is false), but that doesn't stop it either. Thoughts?

Community
  • 1
  • 1
user219142
  • 39
  • 6
  • 1
    There's many solutions to debouncing or throttling event handlers, and that's what you should be looking for, throttling the scroll event. – adeneo Dec 29 '15 at 17:31

3 Answers3

1

Don't use a time out. That is why you are getting in trouble. Declare a variable outside of your function using var, that will make it global. Your code should be inside of a check for that variable. Before executing your code the first time but inside of the check, change that variable so that the code will never run again.

  • The poster states that they tried a global variable but it didn't work, so just suggesting it again without any code showing how to make it work isn't very useful. – blm Dec 29 '15 at 17:49
1

What you're looking for is something along the lines of listenToOnce where the listener fires the one time, but never again. This could be modified to a number of calls, but the logic is like so:

Register the listener.
Then once the listener fires, remove it.

See .off

$(document).on("scroll",function(){

    var arrange_title = function(){
        //some code 
    };

    if($(document).scrollTop()>0){ 
        arrange_title();
        arrange_title = function(){};
        setTimeout(function(){
            $("header").removeClass("large").addClass("small");
            // $(document).off('scroll'); // or here
        },1000);
    }

    $(document).off('scroll'); // remove listener, you can place this in the setTimeout if you wish to make sure that the classes are added/removed
});
SoluableNonagon
  • 11,541
  • 11
  • 53
  • 98
0

Try avoid setTimeout. Almost all animation can be watched for end.

function doHeaderAnimation() {
  return $('header').animate();
}

function makeHeaderSmall() {
  $("header").removeClass("large").addClass("small");
}

function handleScroll(event) {

  if ($(document).scrollTop() > 0) { 

    doHeaderAnimation().then(makeHeaderSmall);

    $(document).off("scroll", handleScroll);

  }

}

$(document).on("scroll", handleScroll);
dsdenes
  • 1,025
  • 6
  • 15