Question

I would like to implement the following animation effect;

http://jsfiddle.net/YKmu2/37/

This is the core code;

    $("#c1").on( "click", function(event) {

    event.preventDefault(); 
    new_site = 'content1';

    if(site == new_site) {   $('[name="' + new_site + '"]').show();   }
    else {  

        $('[name="' + new_site + '"]').insertAfter('[name="' + site + '"]');
        $('[name="' + new_site + '"]').show();
        $.scrollTo('[name="' + new_site + '"]', 1000);

    }   

    setTimeout(function() {     
        $('[name="' + site + '"]').hide();              
        $.scrollTo('[name="' + new_site + '"]');
        site = new_site;                
        }, 1005);

});

When you click on one of the links, the content associated with this link is appended to the current content and a scroll animation is executed using the scrollTo plugin.

After the scroll animation is finished, the old content is removed/hidden.

That works all fine as long as the user is clicking on a link and is waiting until everything is finished. However when you start to click on multiple links while the animation is not finished a lot of weird things are happening.

Does someone have an idea how to fix this / make it reliable and error-proven? Or does somebody know a jquery plugin that already implements such an effect?

Thank you!

Was it helpful?

Solution

This is a relatively common problem of animation queueing and only triggering the action if there are no animations already happening, however in this case you need to be checking if the page is scrolling or not, which is a little more abstract in a sense.

UPDATED BELOW TO FIX SCROLLING ISSUE: I've updated your fiddle here: http://jsfiddle.net/andyface/77fr6/ to demonstrate checking to see if the page has scrolled to the top before triggering a change in content.

Current working fiddle: http://jsfiddle.net/andyface/77fr6/1/

I've also taken some liberties with making your code a little easier to manage, which I hope is actually helpful. Essentially I've made things work based on classes instead of individual IDs, so you only have to maintain one bit of code and if you need to expand it, you don't have to add more blocks of code, just a few extra lines to get the ID, however this could be made to do it all cleverly enough to not even need that.

The main changes I've made are as follows:

  • The links now have a class of link and content a class of content.
  • The IDs of the links are then used to extrapolate the content they are meant to be triggering.
  • I've also removed the timeout and used the scrollTo() callback feature as this will be more reliable.
  • Finally I added a check to see if the page had scrolled to the top before allowing the action to trigger

Hope this helps, but let me know if you need anything more explaining

UPDATE: Seeing I missed the fact that by limiting the action by scroll position this would stop them working if the user scrolled down, I've changed how the action blocking works.

$(document).ready(function() {

    // HIDE CONTENT
    $('.content').hide();

    var site = '',
        scrolling = false;

    $(".link").on( "click", function(event) {

        // THIS IS JUST USED FOR TESTING TO SEE WHAT THE scrollTop() POSTION IS WHEN CONTENT IS SCROLLED - REMOVE console.log() WHEN IN PRODUCTION
        console.log($(window).scrollTop());

        event.preventDefault(); 

        // ONLY RUN THE SCRIPT IF THE PAGE HAS SCROLLED TO IT'S FINAL POSITION
        if( ! scrolling)
        {
            var new_site = null;        

            switch($(this).attr('id')) {

                case 'c1':
                    new_site = 'content1';
                    break;
                case 'c2':
                    new_site = 'content2';
                    break;
                case 'c3':
                    new_site = 'content3';
                    break;
            }

            if(site != new_site) {  

                // KEEP A TRACK OF IF THE PAGE IS SCROLLING OR NOT
                scrolling = true;

                $('#' + new_site).insertAfter('#' + site);
                $('#' + new_site).show();
                $.scrollTo('#' + new_site, 1000, function() {

                    // CALLBACK TRIGGERED WHEN SCROLLING HAS FINISHED
                    $('#' + site).hide();
                    $.scrollTo('#' + new_site);
                    site = new_site;

                    // TELL THE PAGE IT'S OK TO DO STUFF COS WE'RE NOT SCROLLING IT ANYMORE
                    scrolling = false;
                });   
            }   
        }
    });
}); 

http://jsfiddle.net/andyface/77fr6/1/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top