malsup / cycle2

2nd gen cycling
899 stars 236 forks source link

Multiple sliders, pagers and prev/next control all sliders #681

Open sclander opened 9 years ago

sclander commented 9 years ago

I'm trying to use multiple instances of cycle2 on one page. Whenever I use the pager or prev/next buttons on one slider, the action is applied to all sliders on the page. I have distinct IDs for every pager and prev/next button, but the problem is still occurring. Here's a sample of what one of the instances looks like:

<div class="cycle-slideshow lightbox"
    data-cycle-prev="#prev-10606"
    data-cycle-next="#next-10606"
    data-cycle-pager="#pager-10606">

    <!-- IMAGES -->

    <div id="prev-10606" class="cycle-prev"></div>
    <div id="next-10606" class="cycle-prev"></div>
    <div id="pager-10606" class="cycle-prev"></div>
</div>

Any idea what might be causing this?

sclander commented 9 years ago

Update on this, the pagers are actually working correctly. It is only the prev/next buttons that are causing all of the carousels to move. If anyone is out there, please help!

sfregolina commented 9 years ago

Hi!

I have the same problem. Did you solve it? If yes, could you share it here please?

Thanks!

sclander commented 9 years ago

Sorry to give you bad news, but I was never able to solve the issue. I had to remove prev/next controls altogether.

LukeMcGurdy commented 9 years ago

What happens if you try do this by declaring your cycle method directly in your js file? (This is what I normally do anyway.)

For example, something like

// first gallery
    $('#first-gallery ul').cycle({
        fx: 'scrollHorz',
        slides: '>li',
        next: '#first-next',
        prev: '#first-prev'
    });
// Second gallery
    $('#second-gallery ul').cycle({
        fx: 'scrollHorz',
        slides: '>li',
        next: '#second-next',
        prev: '#second-prev'
    });

One thought. I wonder if it is possible to put conditional statements within the method specifically for next:, and prev options. Something like:

if parent = #second-gallery then next: '#second-next', prev: '#second-prev' else next: '#first-next', prev: '#first-prev'

It might make for less repeats.

makbeta commented 8 years ago

This approach is valid, but far from optimal. I had a similar issue & did not see it necessary or sustainable to create unique markup & JS calls for each slider/carousel. My other dilemma was that the slideshow was in a slightly different container than a pager/prev/next for display/functionality reasons.

I found that the most sustainable solution was to update the core code so if the selector for an item is not a child or a sibling, we look for the selector inside the parent container first. Only if we don't find the container in a parent do we start looking for the item globally. This allowed me to keep HTML uniform across slideshows & each pager/navigation to still apply only to the current slideshow.

Here's what my html looks like & I have multiple instances of it.

`

<div class="slideshownavigation> <span class="slideshowprev">

`

The updated code will first look for .slideshowprev inside .slideshow, but then it would look for it inside .slideshowcontainer, before looking for it in all the document.

The code was updated as follows (either in jquery.cycle2.core.js in src or in final built file)

    getComponent: function( name ) {
        var opts = this.opts();
        var selector = opts[name];
        // if selector is a child, sibling combinator, adjancent selector then use find, otherwise query parent element & then full dom
            if ( ( /^\s*[\>|\+|~]/).test( selector ) ) {
                return opts.container.find( selector );
            }  else {
                var inParent = opts.container.parent().find( selector );
                if(inParent.length > 0) {
                    return inParent;
                } else {
                    return $( selector );
                }
            }
        if (selector.jquery) {
            return selector;
        }

        return $(selector); 

    },

Hope this is helpful.

ghost commented 8 years ago

Can confirm this fixes the same issue for me. Many thanks for the solution @makbeta

syberknight commented 7 years ago

@makbeta DUDE... THANK YOU SO MUCH for this hack!!! i'm not very skilled with JS/Jquery (yet) & was racking my brain trying to figure this out. found this thread & it works it works it works. ✌🏼

aaroncrawford commented 6 years ago

For people facing the multiple slideshows issue that cannot use IDs or the different class names, you just need to iterate through all instances of your slideshows e.g. :

$('.galleryContainer').each(function() {
        $(this).cycle({
            slides: '> .slide',  // if not using just images as the children of .galleryContainer.
            pager: $(this).siblings('.galleryControls'), // finding this slideshow's controls box using $this
            timeout: 5000
        })
    })

This will allow multiple slideshows with their own pagers and all based on class names. Useful if building a modular site using the BEM architecture.

dvsobel commented 5 years ago

I am sort of new to code and am trying to figure out what I'm doing wrong here. I've been using basic/vanilla JS and am trying to figure out how to have two galleries with separate next/previous buttons. Can someone please help me figure out what to add to my script or point me in the right direction?

``

makbeta commented 5 years ago

@dvsobel ,

This plugin requires that the jQuery library be installed first, as it is a dependency. Based on the code you are writing it seems like you are trying to do it all from scratch. This may be a good practice but you may be reinventing the wheel. The plugins like this one contain many features that are useful to have and may take some time to write from scratch.

To run multiple slideshows download the patched/fixed version of this plugin here: https://github.com/dnlomnimedia/cycle2

Then you can set up the slideshow either via specific class assignment as specified in the documentation.

Or trigger the slideshow on custom classes with the following code that also relies on jQuery

$('.my-slideshow-class').cycle({
    speed: 600,
    manualSpeed: 100,
    pager: '.my-custom-pager-selector',
});

Hope this helps.

valiermedia commented 4 years ago

This is an old post, but I just ran into this same issue and almost went down the road of looping through each slideshow in js and activating/declaring prev/next buttons that way. The easiest solution is just to make sure that your prev/next buttons are direct children of the slideshow wrapper, see below (this is a carousel variation for video thumbnails but the same solution should work for the OP's question):

<div class="cycle-slideshow"
    data-cycle-fx=carousel
    data-cycle-timeout=0
    data-cycle-slides="> .video"
    data-cycle-carousel-visible=4
    data-cycle-carousel-fluid=true
    data-cycle-prev="> .carousel-prev"
    data-cycle-next="> .carousel-next"
>

<i class="fal fa-angle-left carousel-prev"></i>
<i class="fal fa-angle-right carousel-next"></i>

{{slides go here}}  

</div>

In this solution, I am using fontawesome icons for the prev/next buttons. The key is that each prev/next button needs to be placed directly under the wrapper element, not in a separate wrapper. Then, you assign the buttons like so:

data-cycle-prev="> .carousel-prev" data-cycle-next="> .carousel-next"

The > tells cycle2 to look for direct descendants of this particular slideshow, which in turn causes the prev/next buttons to only interact with the slideshow in which they are contained. You might be able to run this by adding a secondary wrapper around the prev/next buttons, but you would still need the > symbol to declare a direct descendant of the parent slideshow wrapper.