3

I am trying to build a slideshow using the jQuery Cycle plugin that contains another level of nested slideshows within some of the top-level slides.

The main "container" slides slide horizontally, and then—for "container" slides that contain more than one image on the left-hand side—those images slide up vertically.

Sample here, because I imagine it's hard to visualize: http://dl.dropbox.com/u/2890872/js-test/index.html

You'll only get to the second top-level slide before it stops, even thought there are six top-level slides (which is my issue—the second slide only contains one left-hand inner image, which stops the script), but you can see what the intended transitions are and check out the entire code.

The problem is that not all of the secondary slideshows have more than one image, and jQuery Cycle terminates itself if there is one or less images in a slideshow. This termination also terminates the top-level slideshow, since it is stopped and started based on when the secondary slideshow ends. Since the secondary slideshow terminates due to only one "slide", then the next outer top-level slide never gets called. I'm not sure how to adapt the code to get around this.

The js:

<script type="text/javascript">
$(function(){ 
    // init and stop the inner slideshows
    var inners = $('.slide-up').cycle().cycle('stop');

    var slideshow = $('#home-slides').cycle({
        fx: 'scrollHorz',
        speed: 300,
        timeout: 0,
        before: function() {
            // stop all inner slideshows
            inners.cycle('stop');

            // start the new slide's slideshow
            $(this).children().cycle({
                fx: 'scrollUp',
                timeout: 2000,
                autostop: true,
                end: function() {
                    // when inner slideshow ends, advance the outer slideshow
                    slideshow.cycle('next');
                }
            });
        } 
    });
});
</script>

A sample of the html:

<div id="home-slides">
    <div>
        <div class="slide-up">
            <img src="i/home/slideshow/1l-1.jpg" alt="" width="284" height="420" />
            <img src="i/home/slideshow/1l-2.jpg" alt="" width="284" height="420" />
            <img src="i/home/slideshow/1l-3.jpg" alt="" width="284" height="420" />
        </div>
        <img src="i/home/slideshow/1r.png" alt="" width="291" height="420" />
    </div>
    <div>
        <div>
            <img src="i/home/slideshow/2l-1.jpg" alt="" width="284" height="420" />
        </div>
        <img src="i/home/slideshow/2r.jpg" alt="" width="291" height="420" />
    </div>
    <div>
        <div class="slide-up">
            <img src="i/home/slideshow/3l-1.jpg" alt="" width="284" height="420" />
            <img src="i/home/slideshow/3l-2.jpg" alt="" width="284" height="420" />
        </div>
        <img src="i/home/slideshow/3r.png" alt="" width="291" height="420" />
    </div>
    <div>
         …additional slides…
    </div>
</div>

The slideshow terminates at the second #home-slides > div because there is only one image. I've tried removing the nesting and the "slide-up" class from the slides with no inner-slideshow, but that doesn't help.

Again, full working version with all relevant code can be found here: http://dl.dropbox.com/u/2890872/js-test/index.html

----------- EDITED 4/10 - Minor Updates and possibly a lead ----------

I've edited the code here and on the example link just to add some details that elmininate the first thoughts for troubleshooting. Now, only the the slides with secondary slideshows use the class "slide-up".
- I've tried specifying the '.slide-up' class in the function for the "end" callback ('$(this).children('.slide-up').cycle…'), which does prevent cycle from terminating for too few slides, but that only makes it terminate for unmatched elements!

The closest I've gotten is by adding a conditional check to the function in the end callback: (I'm using length to check the existence of a slide-up div. If there's a better way, let me know)

before: function() {
 if ( $(this).children('.slide-up').length != 0 ) {
    // stop all inner slideshows
    inners.cycle('stop');

    // start the new slide's slideshow
    $(this).children('.slide-up').cycle({
        fx: 'scrollUp',
        timeout: 2000,
        autostop: true,
        end: function() {
            // when inner slideshow ends, advance the outer slideshow
            slideshow.cycle('next');
        }
    });
   } else alert('NO INNER SLIDESHOW!');

This eliminates all errors and terminations directly from jQuery Cycle, but the main slideshow still stops at the slide without a secondary slideshow. I think need to put something in the "else" statement related to firing up "slideshow.cycle('next');", but I haven't figured out the proper syntax to get that to work.

----------- EDIT #2 4/10 - ----------

most recent working example: http://dl.dropbox.com/u/2890872/js-test/index2.html

Moving the before function into its own named function to keep things cleaner.

function onBefore(currSlideElement, nextSlideElement, options, forwardFlag) {
     if ( $(this).children('.slide-up').length != 0 ) {
        // stop all inner slideshows
        //inners.cycle('stop');

        // start the new slide's slideshow
        $(this).children('.slide-up').cycle({
            fx: 'scrollUp',
            timeout: 2000,
            autostop: true,
            end: function() {
                // when inner slideshow ends, advance the outer slideshow
                slideshow.cycle('next');
            }
        });
       } 
      // else null;
      else $(this).parent().cycle({ 
        end: function() { slideshow.cycle('next'); }
       });
    } 

This (else statement) allows the slideshow to progress, but it doesn't preserve the original 'slideshow' options, and just starts playing the top-level slides with default out-of-the-box options (fades from one slide to the next, instead of sliding, stops playing secondary slides).

I don't understand: 1) How to preserve the options. (I thought that was why the var "slideshow" was created in the first place)

2) Why an else statement is even necessary—I don't understand why the outer slides are stopping at all when the conditional '.slide-up' statement isn't executed— I would think the outer slideshow would just continue as normal.

Kerri
  • 1,211
  • 2
  • 15
  • 22
  • I wish I could take credit for it, but it's very slightly adapted from the examples page here: http://jquery.malsup.com/cycle/more.html?v2.23 – Kerri Apr 09 '11 at 20:16
  • I use cycle whenever I can, it's a beautiful plugin that does everything I need. – The Muffin Man Apr 09 '11 at 20:21
  • Regarding the second update: 1. Did you try using the options object that's being passed as a parameter? There's also a options.$cont variable that you can use. I guess it refers to the parent cycle. 2. That was my though too. I was wondering if the callback function should return a particular value, but apparently its not necessary. – Zero Apr 11 '11 at 03:08
  • Solved! See the answer I added today. – Kerri Apr 11 '11 at 18:56

4 Answers4

2

A facebook friend solved it! Thanks, facebook friend!

var slideshow = $('#home-slides').cycle({
    fx: 'scrollHorz',
    speed: 300,
    timeout: 0,
    before: function(curElement, nextElement, options, forwardFlag) {
        if($(nextElement).children('.slide-up').length != 0) {
            $(nextElement).children('.slide-up').cycle({
                fx: 'scrollUp',
                timeout: 2000,
                autostop: true,
                end: function() { slideshow.cycle('next'); }
            });
        }
        else {
            setTimeout(function(){ slideshow.cycle('next'); }, 2000);
        }
    }
});

Working example here: http://dl.dropbox.com/u/2890872/js-test/index3.html I need to study Cycle a bit more and the changes he's made to fully understand the role of 'nextElement' in this code, but it most certainly works!

Kerri
  • 1,211
  • 2
  • 15
  • 22
  • It works...however, I had to change the condition to `if($(nextElement).children('.slide-up').length > 1)`in order to make it work with http://jquery.malsup.com/cycle/nest2.html. If you use this condition, your dropbox code will work even if the "one image divs" have class 'slide-up' for consistency. Thanks for posting this awesome solution. – Zero Apr 12 '11 at 02:09
1

Check if this approach helps you: http://www.devcha.com/2010/05/fixed-cycle-terminating-too-few-slides.html

Did you check this question...looks similar problem, but different approach: Nested jQuery Cycle?

Community
  • 1
  • 1
Zero
  • 728
  • 1
  • 7
  • 15
  • Wow, you posted as I was editing my post, and I had just tried something very similar (see my updates). My problem now is getting the main slideshow started back up again. – Kerri Apr 10 '11 at 18:36
  • Not sure about the code to invoke in the else part. $('#slideshow').cycle('next'); doesn't work. It send the browser into an infinite loop. Also, the example here (http://jquery.malsup.com/cycle/nest2.html) doesn't appear to be right. I don't see the need for the following lines: var inners = $('.inner-slideshow').cycle().cycle('stop'); and inners.cycle('stop'); – Zero Apr 10 '11 at 22:09
  • I am trying to create a nested slideshow as you are (that's how I found your question via google)...so please post if you find a solution. – Zero Apr 10 '11 at 22:15
  • I had the same problem with every variation I tried in the else part (I was going down a similar path to what you quoted, but also tried variations of getting back to the outer slideshow from $(this)). No go. (Literally. It won't go!). Now that I think about it, I agree that those two lines don't seem necessary—since (if I understand it correctly), only the inner slideshow for the current outer div is called. At any rate, it doesn't make a difference in starting up the outer show again. I'll definitely keep this question current w/ findings. – Kerri Apr 10 '11 at 22:29
  • Also, if you end up using a completely different script to accomplish this, please let me know as well. I'd prefer to stick with Cycle, since it's used elsewhere throughout the site, but mostly, I prefer to get this done! – Kerri Apr 10 '11 at 22:30
  • A *tiny* bit closer—see recent update. Keeping this updated in case my baby steps inspire a real solution! – Kerri Apr 11 '11 at 00:15
  • I have contacted the author @malsup via twitter. I hope he responds. – Zero Apr 11 '11 at 03:11
0

After I "awarded" the cycle plugin as the best and simpliest slideshow plugin ever, I put some eyes more on it, and did some experiments and spent some hours with it. Results: 1. the cycle().cycle('stop') as same as just cycle('stop') never worked properly, it stops the inner slideshows after every 2nd content. I changed it into a single cycle({timeout:0})... which I do not really understand, but it works absolutely fine, including firebug reviews on js activity. 2. As I needed it to be working on more than just one usage per page, and the aibility to auto-decision, if controls are needed or not, so I changed a couple of things and put the entire js in the $(document).ready(function() {} in the header of the page. The first .inner-slideshow gets an added class="active" from serverside php script.

The code now looks like that

//-----------------jquery cycle plugin modified by Michael Gerner, ddlab, 2012-01-15---------------
$('.slideshow').each(function(){

    var sl = $(this);
    var sl_index = sl.index('.slideshow');
    var allinner = sl.find('.inner-slideshow');
    var firstinner = sl.children('.inner-slideshow:eq(0)');

    //----settings outer slideshow
    var outerfx = 'scrollHorz';
    var outerspeed = 500;
    var outertimeout = 0;
    var outerprev = '#sl'+sl_index+'prev';
    var outernext = '#sl'+sl_index+'next';

    //----settings inner slideshow
    var innerfx = 'fade';
    var innerspeed = 2000;
    var innertimeout = 6000;

    if (allinner.size() > 1) { //---------more than one inner slideshow
        var setcontrols = '<div class="slideshow-controls"><a class="prev" id="sl'+sl_index+'prev" href="#"></a> <a class="next" id="sl'+sl_index+'next" href="#"></a></div>';
        sl.after(setcontrols);
        var controls_a = sl.find('.slideshow-controls a');

        controls_a.click(function(){
            var activeinners = sl.find('.active');
            activeinners.each(function(){
                $(this).removeClass('active').cycle({timeout:0});
            });
        });

        sl.cycle({
            fx:outerfx,
            speed:outerspeed,
            timeout:outertimeout,
            prev:outerprev,
            next:outernext,
            before:function(){
                var activeinners = sl.find('.active');
                activeinners.each(function(){
                    $(this).removeClass('active').cycle({timeout:0});
                });
            },
            after:function(){
                $(this).addClass('active').cycle({
                    fx:innerfx,
                    speed:innerspeed,
                    timeout:innertimeout,
                    autostop: true,
                    end: function() { sl.cycle('next'); }
                });
            }
        });
    }
    else { //------------just one inner slideshow
        firstinner.cycle({
            fx:innerfx,
            speed:innerspeed,
            timeout:innertimeout
        });
    }
});
//-----------------jquery cycle plugin modified by Michael Gerner, ddlab, 2012-01-15---------------

Now I am happy with it, specially the browserload on js activity is extremely small, which I want to point out as important for mobile devices, and finally I added some frontend-editing tools, such as html5upload and a jq-filemanager, which is used for the owner of the website to manage the content for the gallery.

Thanks for all previous reviews and tuts, that helped me a lot to get this track :-) You may find a lightweight screenshot image (26kb) on here http://ddlab.de/screenshots/cycle_gallery.jpg

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
ddlab
  • 918
  • 13
  • 28
0

I uploaded the working example here http://ferienhaus-fischland-ahrenshoop.de/mini4/ After finishing this project in the near future, you´ll find the gallery anywhere on this page http://ferienhaus-fischland-ahrenshoop.de probably on the start page and others.

ddlab
  • 918
  • 13
  • 28