views:

131

answers:

4

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?

A: 

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.

Gabriel Hurley
+1  A: 

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.

MiffTheFox
nice. one might also unbind on the click, then re-bind after the process completes.
Matt Sherman
Doesn't work because the slideUp/slideDown happen asynchronously. i.e. scrollDownClickActive = false happends before the slide finishes.
Prestaul
@Prestaul - Fixed that problem by using the slideUp callback parameter.
MiffTheFox
Hi, I just wanted to say thanks for this answer, its taught me lots of new stuff and I've used the syntax's elsewhere now - thank you!
Tristan
A: 

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.

Prestaul
A: 

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!

thephpdeveloper