Tristan Brotherton
Tristan Brotherton

Reputation: 2571

jQuery .click function - prevent it from being called again until function completes

I've written my first bit of proper jQuery for an image slideshow, that allows users to scroll up and down through some images:

$(window).load(function(){

    $('.scrollUp').click(function(){ 
    $('.cardWrapper:visible:first').prevAll(':hidden:first').slideDown(function(){
        $('.cardWrapper:visible:last').slideUp();
        });
    return false;
    });


    $('.scrollDown').click(function(){
    if($('.cardWrapper:last').is(':hidden')){
    $('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
    $('.cardWrapper:visible:first').slideUp();
    }

    else{
        $('.cardWrapper:last').after('<div class="cardWrapper"></div>');        
            $('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
            $('.cardWrapper:visible:first').slideUp();
            }); 
        }
        return false;
    });
});

The problem I have is that if you click very fast on the .scrollDown element link - it loses all the content as it hasn't had the time to add the extra ( i think) - and thus it starts to fail.

Is there a way to make jQuery not accept any new click on an element until its run all of this function?

Upvotes: 0

Views: 917

Answers (4)

mauris
mauris

Reputation: 43619

The use of binding and unbinding removes the use of flag variables =)

function scroller(obj){
    $(obj).unbind('click');
    if($('.cardWrapper:last').is(':hidden')){
            $('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
            $('.cardWrapper:visible:first').slideUp();
            scrollDownClickActive = false;
    }
    else
    {
            $('.cardWrapper:last').after('<div class="cardWrapper"></div>');                
            $('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
                    $('.cardWrapper:visible:first').slideUp();
                    scrollDownClickActive = false;
            });     
    }
    $(obj).click(function(){scroller(this);});
}

$('.scrollDown').click(function(){
     scroller(this);        
});

Hope this helps!

Upvotes: 1

MiffTheFox
MiffTheFox

Reputation: 21575

Maybe something like

var scrollDownClickActive = false;

$('.scrollDown').click(function(){
    if (scrollDownClickActive) return false;
    scrollDownClickActive = true;

    if($('.cardWrapper:last').is(':hidden')){
        $('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
        $('.cardWrapper:visible:first').slideUp(200, function(){ scrollDownClickActive = false; } );
    }
    else
    {
        $('.cardWrapper:last').after('<div class="cardWrapper"></div>');                
        $('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function(){
            $('.cardWrapper:visible:first').slideUp(200, function(){ scrollDownClickActive = false; } );
        });     
    }
    return false;
});

Using a flag to determine if the function is active or not.

Upvotes: 1

Prestaul
Prestaul

Reputation: 85224

You can use a flag to indicate that it is scrolling (as suggested by MiffTheFox), but you'll have to unset the flag in the slide callback because the slide happens asynchronously:

$(function(){
    var scrolling = false;

    function startScrolling() {
        if(scrolling) return false;
        return scrolling = true;
    }
    function scrollComplete() {
        scrolling = false;
    }

    $('.scrollUp').click(function() {
        if(startScrolling()) return false;

        $('.cardWrapper:visible:first')
            .prevAll(':hidden:first').slideDown(function() {
                $('.cardWrapper:visible:last').slideUp(scrollComplete);
            });

        return false;
    });

    $('.scrollDown').click(function() {
        if(startScrolling()) return false;

        if($('.cardWrapper:last').is(':hidden')) {
            $('.cardWrapper:visible:last').nextAll(':hidden:first').slideDown();
            $('.cardWrapper:visible:first').slideUp(scrollComplete);
        } else {
            $('.cardWrapper:last').after('<div class="cardWrapper"></div>');
            $('.cardWrapper:last').load('/followedTestSingle/?sequence={{gr.sequence_token}}', function() {
                $('.cardWrapper:visible:first').slideUp(scrollComplete);
            });
        }
        return false;
    });
});

Disclaimer: I haven't checked your code to see how valid it is, I've just added the flag and the callbacks for you.

Upvotes: 0

Gabriel Hurley
Gabriel Hurley

Reputation: 40082

If it's clicking an button element, just have your function disable it and re-enable it in the completion callback function.

Otherwise just write your function to check for a variable value which prevents it from running. If the variable isn't set, have it set a the value (something like var busy = true;) in the handler and set it back to false in the completion callback.

Upvotes: 0

Related Questions