darsain / sly

JavaScript library for one-directional scrolling with item based navigation support.
http://darsa.in/sly
2.87k stars 497 forks source link

Active item position and Slidee position isn't restored on sly.reload() #257

Open sergey-dev opened 8 years ago

sergey-dev commented 8 years ago

I have really ordinary initialization and logic on Sly, but gotten annoying issue, which I can't solve without hacking into the Sly itself.

var slyOptions = {                                       
    horizontal: true,                                    
    itemNav: 'basic',                                    
    speed: 300,                                          
    mouseDragging: false,                                
    touchDragging: true,                                 
    // controls to navigate                              
    nextPage: $navRight,                                 
    prevPage: $navLeft,                                  
    // navigate to active position, if applicable        
    startAt: activeElementPosition                       
};                                                       
slyInstance = new Sly($frameSelector, slyOptions).init();

I have to recalculate the responsive breakpoints and to update the widths of elements on every window resize, so I'm wiping inline styles on them (alike $(selector).removeAttr('style') which Sly applied, and then re-calculating widths for elements and re-applying Sly:

slyInstance.reload()

it works smoothly, everything is fine, except one huge drawback: in case slyInstance.rel.activeItem had something different from zero position, the SLIDEE's position and styles position for transform: translateZ(0px) translateX(.....) isn't re-calculated again.

So visual appearance in DOM and internal state of slyInstance goes out of sync on slyInstance.reload(). That is the SLIDEE has viewport pointing to the zero element after reload, but internally rel.activeItem, rel.centerItem, etc are still having an old values. I think Sly internally has to refresh/update SLIDEE position on reload() and to recalculate the fresh transform value for the style as well.

I think this code has to be invoked on reload(), in the same way is happens on init and render, here's the code snippet which responsible for that:

// Update SLIDEE position                                                                                                       
if (!parallax) {                                                                                                                
    if (transform) {                                                                                                            
        $slidee[0].style[transform] = gpuAcceleration + (o.horizontal ? 'translateX' : 'translateY') + '(' + (-pos.cur) + 'px)';
    } else {                                                                                                                    
        $slidee[0].style[o.horizontal ? 'left' : 'top'] = -round(pos.cur) + 'px';                                               
    }                                                                                                                           
}                                                                                                                               

Separately from that, please, don't forget to return sly instance reference, when slyInstance.reload() method is invoked, just to be consistent, and to make possible the further commands chaining.

David-Bascom commented 7 years ago

Had the same problem. Here is my solution:

if you use the classic new Sly() initialization: var mySly = new Sly('.chronik .frame', options ).init();

then you can use this script to reload the slider without losing the scroll-position:

var x = mySly.rel.centerItem;
mySly.reload();
mySly.toCenter( x, true );

In case you prefer using the jQuery-proxy: var $mySly = $('.my-item').sly( options );

then here is a useful jQuery-extension to refresh the slider:

(function ($) {

    $.fn.extend({
        'rebuildSly': function () {
            return this.each( function () {
                var slyInstance = Sly.getInstance( this );
                var x = slyInstance.rel.centerItem;
                slyInstance.reload();
                slyInstance.toCenter( x, true );
            });
        }   
    });

})(jQuery);

it can simply be used like this:

var $mySly = $('.my-item').sly( options );
// ... then do something like add items or resize ...
$mySly.rebuildSly();
David-Bascom commented 7 years ago

Update: In certain situations the solution above does not work correctly, i.e. after adding the new Elements using jQuery.append( items );. I came up with a workaround by delaying the sly.rebuild() call by a millisecond. This also solved the problem of my sly jumping back to the first element after rebuild()

var mySly = new Sly('.sly-thing', options).init();

// Append items to Sly using jQuery, i.e after an AJAX call that returns the new elements
$('.slyslider-content').append( $newItems );

// Wait a millisecond before you rebuild the sly
setTimeout(function () {
  mySly.rebuild();
},1);
ltechie commented 2 years ago

Hi, i am using sly slider, where im into requirement of showing active element visible when page loads intially, user need not to scroll to find active element, i have added startAt:activeElementPosition and itemNav: 'basic',but still its not coming.