vasyabigi / angular-slick

Angular directive for slick-carousel
http://vasyabigi.github.io/angular-slick/
MIT License
500 stars 237 forks source link

Flash of un-initialized content with dynamic data #81

Open JonCognioDigital opened 9 years ago

JonCognioDigital commented 9 years ago

I'm using init-onload="items" because my slides are inside an ng-repeater.

The trouble is that since I changed the slides from static to Angular/repeater I find that all of the slides flash in a column before being initialized into a row. This doesn't seem to happen when they are hard coded as static slides in the HTML. Does anybody know how this can be fixed?

dirkbartels14050 commented 9 years ago

For what it is worth, I am using angular-slick and do not have any issue. Here is part of my code:

<div class="row">

<slick init-onload="true" infinite="false" slides-to-scroll="1" swipe-to-slide="true" touch-move="true"
touch-threshold="1000" dots="false" responsive="breakpoints" edge-friction="0" data="entries"
class="slider lazy" css-ease="linear" style="max-width:1024px; margin-bottom: 10px">

<div ng-repeat="entry in entries" class="untventry" style="position:relative;">
    <a href="#/entry/{{entry.linkName}}?list={{selectedCat.name}}">
    <div id="entry" class="mycontainer"> 
    <img id="entryimage" ng-src="{{entry.imageUrl}}" style="  -webkit-filter: grayscale(100%); filter:grayscale(100%)"/>
Kenishi commented 9 years ago

I'm not sure if this will help you but I had a similar issue and fixed it somewhat this way. The elements still flash briefly and it causes elements still move around, but I don't end up with a giant list not in a carousel. If you want it 100%, then make sure to call your beforeSlick() before you initialize/update the carousel data. My situation is a little unique too because my carousel data is dynamic (updates via socket.io) and the DOM wasn't updating, I found the ng-if worked to trigger angular to redraw the DOM. Anyway, you can give this a shot.

In the angular slick JS file:

 scope: {
   ....
    prevArrow: '@',
    nextArrow: '@',
    // I'm not 100% sure these need to be '=' but this is what worked for me
    beforeLoad: '=',
    afterLoad: '='
 }
 link: function (scope, element, attrs) {     
   ....
   initializeSlick = function () {
        var currentIndex, customPaging, slider;
        slider = $(element);

        // Let the controller know we are about to slick it
        if(scope.beforeSlick) {
          scope.beforeSlick();
        }
      ....

      slider.on('afterChange', function (event, slick, currentSlide) {
          if (scope.onAfterChange) {
            scope.onAfterChange(slick, currentSlide);
          }

          if (currentIndex != null) {
            return scope.$apply(function () {
              currentIndex = currentSlide;
              return scope.currentIndex = currentSlide;
            });
          }
       });

        if(scope.afterSlick) { 
          // We call the callback in timeout to make sure everything has been slicked
          $timeout(function() {
            scope.afterSlick();
          });
        }

Here's some Jade showing how I'm doing it:

 slick(ng-if="dataLoaded" before-slick="beforeSlick" after-slick="afterSlick" init-onload="true" infinite="true" data="entries" )
    div.listItem(ng-repeat="entry in entries")
        .row
            .col-sm-12
                img(ng-src="{{url}}")
        .row
            .col-sm-12
                span {{entry.text}}

In the controller.js that the carousel sits in:

 $scope.beforeSlick = function() {
     $(".listItem").hide();
 };
 $scope.afterSlick = function() {
     $(".listItem").show();
 };
mhulse commented 9 years ago

@Kenishi I think your example code should be:

scope: {
    data: '=',
    initialSlide: '@',
    beforeSlick: '=',
    afterSlick: '='
    // ... options ...
},

Thanks for sharing.

rg-najera commented 8 years ago

@jon64digital Not sure if you used one of the solutions above, what I did was to make the wrapping element width span the 9 items Im initially loading, in the largest state available and floated them to the left before the slick dom elements are generated and slick-initialized is added as a class.

/ Handles view before Slick Initializes
slick:not(.slick-initialized) {
  min-width: 2,048px;
  display: block;
  .video-wrap {
    float: left;
    margin-right: $line-height-computed/2;
  }
}

This mimics the position. of when slick is initialized. We also found that lazy loading is absolutely needed for our case, so we limited our initial load to 9 items per slider and have 3 displaying.

Would say that you can pair it with @Kenishi 's solution as well. So we all know that this repo is not very well maintained, you should checkout this issue slick/issues/1005 - regarding https://github.com/kenwheeler/slick/issues/1005 so that the on-load executes in the correct manner.

Also see https://github.com/vasyabigi/angular-slick/pull/100

on Slick.js dist we ended up with:

if (attrs.onInit) {
    scope.onInit();
  }
  if (typeof currentIndex !== "undefined" && currentIndex !== null) {
    return sl.slideHandler(currentIndex);
  }
});

slider.slick({
 ....
});

slider.on('reInit', function(sl) {
  if (attrs.onReInit) {
    return scope.onReInit();
  }
});

slider.on('setPosition', function(sl) {
  if (attrs.onSetPosition) {
    return scope.onSetPosition();
  }
});

slider.on('swipe', function(sl) {
  if (attrs.onSwipe) {
    return scope.onSwipe();
  }
});

slider.on('breakpoint', function(sl) {
  if (attrs.onBreakpoint) {
    return scope.onBreakpoint();
  }
});

slider.on('destroy', function(sl) {
  if (attrs.onDestroy) {
    return scope.onDestroy();
  }
});

slider.on('edge', function(sl) {
  if (attrs.onEdge) {
    return scope.onEdge();
  }
});
carinafu commented 8 years ago

@jon64digital hey, have you solved this problem, I got the same issue. I have tried @Kenishi method, but it does not work for me

annezao commented 8 years ago

@Kenishi Thank you so much! This method really works for me.