Override JCarousel's navigation functions while keeping personnal (overrided) code synchronized with the carousel

2.4k views Asked by At

I added some JS code to the next and previous buttons like this :

$('.jcarousel-control-prev').on('click', function(){
    updateCurrentPhotoId(-1);
    return false;
});
$('.jcarousel-control-next').on('click', function(){
    updateCurrentPhotoId(+1);
    return false;
});

So I know which image is currently displayed (only one at a time in my case) and I can show content related to the image.

My problem is when I click Next (or Previous) very fast: the image changes slowly (Even if I click twice in the same second, "only one Next is applied" (it doesn't break the animation to apply my two clicks nor does it remembers, after showing the next image, that I clicked twice and that it should "do Next" one more time) BUT my code (updateCurrentPhotoId) is executed every time I click.

So, to be clear, if I'm on the first image and I click 3 times very fast on Next, the currentPhotoId is incremented 3 times (that's cool) but the second image is displayed, not the third one. If I click normally (I wait till the animation is done to click Next again), it's ok. But if I'm too fast, my counter and the carousel aren't synchronized anymore (so the data displayed is not related to the displayed photo...).

I thought I could add some delay to my functions, equal to the animation duration, but I don't know how.

And, as I can see on that example, there must be an easy way to "synchronize actions with animations" (on that example, try to click on the thumbnails below the carousel very fast, you'll see that you have to wait the image has been changed to be able to select another image) but I don't understand where is the magic in that code (maybe in the bolded function?).

This is the code of the example :

(function($) {
// This is the connector function.
// It connects one item from the navigation carousel to one item from the
// stage carousel.
// The default behaviour is, to connect items with the same index from both
// carousels. This might _not_ work with circular carousels!
var connector = function(itemNavigation, carouselStage) {
    return carouselStage.jcarousel('items').eq(itemNavigation.index());
};

$(function() {
    // Setup the carousels. Adjust the options for both carousels here.
    var carouselStage      = $('.carousel-stage').jcarousel();
    var carouselNavigation = $('.carousel-navigation').jcarousel();

    // We loop through the items of the navigation carousel and set it up
    // as a control for an item from the stage carousel.
    // ** Here is the "bolded" function **
    carouselNavigation.jcarousel('items').each(function() {
        var item = $(this);

        // This is where we actually connect to items.
        var target = connector(item, carouselStage);

        item
            .on('jcarouselcontrol:active', function() {
                carouselNavigation.jcarousel('scrollIntoView', this);
                item.addClass('active');
            })
            .on('jcarouselcontrol:inactive', function() {
                item.removeClass('active');
            })
            .jcarouselControl({
                target: target,
                carousel: carouselStage
            });
    });

    // Setup controls for the stage carousel
    $('.prev-stage')
        .on('jcarouselcontrol:inactive', function() {
            $(this).addClass('inactive');
        })
        .on('jcarouselcontrol:active', function() {
            $(this).removeClass('inactive');
        })
        .jcarouselControl({
            target: '-=1'
        });

    $('.next-stage')
        .on('jcarouselcontrol:inactive', function() {
            $(this).addClass('inactive');
        })
        .on('jcarouselcontrol:active', function() {
            $(this).removeClass('inactive');
        })
        .jcarouselControl({
            target: '+=1'
        });

    // Setup controls for the navigation carousel
    $('.prev-navigation')
        .on('jcarouselcontrol:inactive', function() {
            $(this).addClass('inactive');
        })
        .on('jcarouselcontrol:active', function() {
            $(this).removeClass('inactive');
        })
        .jcarouselControl({
            target: '-=1'
        });

    $('.next-navigation')
        .on('jcarouselcontrol:inactive', function() {
            $(this).addClass('inactive');
        })
        .on('jcarouselcontrol:active', function() {
            $(this).removeClass('inactive');
        })
        .jcarouselControl({
            target: '+=1'
        });
    });
})(jQuery);

And this is my complete JCarousel initialization code :

    var carouselCurrentPhoto = 1;

function updateCurrentPhotoId(increment){
    carouselCurrentPhoto += increment;

    var photoCount = <?php echo count($project['Photo']); ?>;

    if(carouselCurrentPhoto <= 0){
        carouselCurrentPhoto = photoCount;
    }else if(carouselCurrentPhoto > photoCount){
        carouselCurrentPhoto = 1;
    }

    loadPhoto();
}

function loadPhoto(){
    var descriptionDiv = $('#description_photo_' + carouselCurrentPhoto)[0];
    $('#photo_description')[0].innerHTML = descriptionDiv.innerHTML;
}

(function($) {
    $(function() {
        /* Carousel initialization */
        $('.jcarousel')
            .jcarousel({
                wrap: 'circular',
            });

        /* Prev control initialization */
        $('.jcarousel-control-prev')
            .on('jcarouselcontrol:active', function() {
                $(this).removeClass('inactive');
            })
            .on('jcarouselcontrol:inactive', function() {
                $(this).addClass('inactive');
            })
            .jcarouselControl({
                target: '-=1'
            });

        /* Next control initialization */
        $('.jcarousel-control-next')
            .on('jcarouselcontrol:active', function() {
                $(this).removeClass('inactive');
            })
            .on('jcarouselcontrol:inactive', function() {
                $(this).addClass('inactive');
            })
            .jcarouselControl({
                // Options go here
                target: '+=1'
            });

        $('.jcarousel-control-prev').on('click', function(){
            updateCurrentPhotoId(-1);
            return false;
        });
        $('.jcarousel-control-next').on('click', function(){
            updateCurrentPhotoId(+1);
            return false;
        });

        /* Pagination initialization */
        $('.jcarousel-pagination')
            .on('jcarouselpagination:active', 'a', function() {
                $(this).addClass('active');
            })
            .on('jcarouselpagination:inactive', 'a', function() {
                $(this).removeClass('active');
            })
            .jcarouselPagination({
            });
    });
})(jQuery);

$(document).ready(function (){
    loadPhoto();
});

Thank you for your help!

1

There are 1 answers

0
Philipili On BEST ANSWER

To add code to the Next and Previous buttons, use the method attribute of the buttons initialization code like this (in the control options part) :

$('.jcarousel-control-prev')
    .on('jcarouselcontrol:active', function() {
        $(this).removeClass('inactive');
    })
    .on('jcarouselcontrol:inactive', function() {
        $(this).addClass('inactive');
    })
    .jcarouselControl({
        target: '-=1',
        'method': function(){
            this.carousel()
                // Following line must be there to keep the initial action (scroll to the previous image in this case)
                // and it uses a callback function where we can put the additional code
                .jcarousel('scroll', this.options('target'), function(){
                    // So here is my code, which is now always synchronized with the carousel state
                    updateCurrentPhotoId(-1);
                });      
            }
    });