malsup / cycle2

2nd gen cycling
899 stars 238 forks source link

Cycle 2 - Adding slides dynamically breaks cycle-carousel-wrap #737

Open webdevbrian opened 8 years ago

webdevbrian commented 8 years ago

Hi.

Dynamically adding the slides with this example:

$('#postSelector').cycle('add', '<div>'+post['featuredImage']+'</div>');

Where the post featuredimage is an image tag, with it's source etc.

What is happening to the markup is this : http://d.pr/i/1cQTu/12mgSmTM

It's creating the slides correctly at first it looks like, then for some reason it's taking two of those slides and dumping them below and outside of the .cycle-carousel-wrap, thus breaking the whole thing.

I really want to use cycle2 ... but I can't obviously if it doesn't work with dynamically adding slides.

thanks

therealthing commented 8 years ago

+1

LukeTowers commented 8 years ago

The issue is that the carousel plugin wraps the slides in a div on initialization and animates the div to create the carousel effect. I'm looking into ways to modify the API.add function to support this right now, however the issue is made more difficult to fix via the method that is used to wrap slides for a continuous loop.

Edit: Also duplicate of #281

// transition API impl
    postInit: function( opts ) {
        var i, j, slide, pagerCutoffIndex, wrap;
        var vert = opts.carouselVertical;
        if (opts.carouselVisible && opts.carouselVisible > opts.slideCount)
            opts.carouselVisible = opts.slideCount - 1;
        var visCount = opts.carouselVisible || opts.slides.length;
        var slideCSS = { display: vert ? 'block' : 'inline-block', position: 'static' };

        // required styles
        opts.container.css({ position: 'relative', overflow: 'hidden' });
        opts.slides.css( slideCSS );

        opts._currSlide = opts.currSlide;

        // wrap slides in a div; this div is what is animated
        wrap = $('<div class="cycle-carousel-wrap"></div>')
            .prependTo( opts.container )
            .css({ margin: 0, padding: 0, top: 0, left: 0, position: 'absolute' })
            .append( opts.slides );

        opts._carouselWrap = wrap;

        if ( !vert )
            wrap.css('white-space', 'nowrap');

        if ( opts.allowWrap !== false ) {
            // prepend and append extra slides so we don't see any empty space when we
            // near the end of the carousel.  for fluid containers, add even more clones
            // so there is plenty to fill the screen
            // @todo: optimzie this based on slide sizes

            for ( j=0; j < (opts.carouselVisible === undefined ? 2 : 1); j++ ) {
                for ( i=0; i < opts.slideCount; i++ ) {
                    wrap.append( opts.slides[i].cloneNode(true) );
                }
                i = opts.slideCount;
                while ( i-- ) { // #160, #209
                    wrap.prepend( opts.slides[i].cloneNode(true) );
                }
            }

            wrap.find('.cycle-slide-active').removeClass('cycle-slide-active');
            opts.slides.eq(opts.startingSlide).addClass('cycle-slide-active');
        }

        if ( opts.pager && opts.allowWrap === false ) {
            // hide "extra" pagers
            pagerCutoffIndex = opts.slideCount - visCount;
            $( opts.pager ).children().filter( ':gt('+pagerCutoffIndex+')' ).hide();
        }

        opts._nextBoundry = opts.slideCount - opts.carouselVisible;

        this.prepareDimensions( opts );
    },
LukeTowers commented 8 years ago

So, this still doesn't help you with carousel's where allowWrap is true, but if you have a carousel that isn't using wrapping, then you can add the following code to jquery.cycle2.carousel.js's cycle-bootstrap function.

// override default 'add' function
    API.add = function( slides, prepend ) {
        var opts = this.opts();
        var oldSlideCount = opts.slideCount;
        var startSlideshow = false;
        var len;

        if ( $.type(slides) == 'string')
            slides = $.trim( slides );

        $( slides ).each(function(i) {
            var slideOpts;
            var slide = $(this);

            if (opts._carouselWrap) {
                if ( prepend )
                    opts._carouselWrap.prepend( slide );
                else
                    opts._carouselWrap.append( slide );             
            } else {
                if ( prepend )
                    opts.container.prepend( slide );
                else
                    opts.container.append( slide );
            }

            opts.slideCount++;
            slideOpts = opts.API.buildSlideOpts( slide );

            if ( prepend )
                opts.slides = $( slide ).add( opts.slides );
            else
                opts.slides = opts.slides.add( slide );

            opts.API.initSlide( slideOpts, slide, --opts._maxZ );

            slide.data('cycle.opts', slideOpts);
            opts.API.trigger('cycle-slide-added', [ opts, slideOpts, slide ]);
        });

        opts.API.updateView( true );

        startSlideshow = opts._preInitialized && (oldSlideCount < 2 && opts.slideCount >= 1);
        if ( startSlideshow ) {
            if ( !opts._initialized )
                opts.API.initSlideshow();
            else if ( opts.timeout ) {
                len = opts.slides.length;
                opts.nextSlide = opts.reverse ? len - 1 : 1;
                if ( !opts.timeoutId ) {
                    opts.API.queueTransition( opts );
                }
            }
        }
    };

The key part of the new API.add function is in the $( slides ).each() function:

if (opts._carouselWrap) {
                if ( prepend )
                    opts._carouselWrap.prepend( slide );
                else
                    opts._carouselWrap.append( slide );             
            } else {
                if ( prepend )
                    opts.container.prepend( slide );
                else
                    opts.container.append( slide );
            }