4

I have a this function

function toDiv() {
$(".wrap"))) 

    $('.barfill').each(function(){
        var width=$(this).data('width');
        $(this).animate({ width: width }, 500);
        var $perctext = $('<div>', {'class': 'perctext', text: width});
        $perctext.appendTo(this);
        $perctext.delay(500).each(function(a) {
            $(this).delay(a * 250).animate({
            'left': width
        }, 1000);
    });
}); 
else {}
}

that runs after the element appears on the pane by using this.

function toView(elem) {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();
    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

I want it to run ONCE and when the element is on the pane again the function won't trigger again.

I applied .one() to the parent function so it runs only once but that didn't do the trick.

You can check the Fiddle Demo to clarify the problem further.



Note: I updated this question for clarity, since it seemed to create some misunderstandings.

Hélio C
  • 143
  • 9

3 Answers3

5

Use .unbind() to remove the listener once it's been used:

$(window).scroll(toDiv);

function toView(elem) {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();
    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

function toDiv() {

    if (toView(
    $(".wrap"))) {
        $('.barfill').each(function () {
            var width = $(this).data('width');
            $(this).animate({
                width: width
            }, 500);
            var $perctext = $('<div>', {
                'class': 'perctext',
                text: width
            });
            $perctext.appendTo(this);
            $perctext.delay(500).each(function (a) {
                $(this).delay(a * 250).animate({
                    'left': width
                }, 1000);
            });
        });
      $(window).unbind('scroll');
    }
}

JSFiddle

SomeKittens
  • 38,868
  • 19
  • 114
  • 143
  • Accepted and upvoted. Quick question: unbind is a better practice over creating the flag to check if it was executed? Or is simply the short/cleaner way to achieve it? – Hélio C Apr 06 '14 at 00:19
  • 2
    @HélioC Unbind is better practice, I just had a brain fart. Sorry about that. – SomeKittens Apr 06 '14 at 00:22
1
function highlander(fn) {
  return function() [
    if (fn) {
      fn.apply(this, arguments);
      fn = null;
    }
  }
}

var printHello = highlander(function() {
  console.log('Hello');
});

printHello();
printHello();
printHello();
// will print hello only once!
Daniel Baulig
  • 10,739
  • 6
  • 44
  • 43
0

Your solution should be found, simply, in the original counter principle.

// define a counter
var counter = 0;
$(window).scroll(toDiv);
function toView(elem) {
    //check the counter value
    if (counter > 0) return false;      
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();    
    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));

}
function toDiv() {
    if (toView(
        $(".wrap"))) 

        $('.barfill').each(function(){
            // increase the counter value
            counter++;
            var width=$(this).data('width');
            $(this).animate({ width: width }, 500);
            var $perctext = $('<div>', {'class': 'perctext', text: width});
            $perctext.appendTo(this);
            $perctext.delay(500).each(function(a) {
                $(this).delay(a * 250).animate({
                    'left': width
                }, 1000);
            });
        });

    else {

         }

}

Checkout the DEMO

SaidbakR
  • 13,303
  • 20
  • 101
  • 195