Slick Carousel with Angular JS
Asked Answered
K

2

15

I am using Slick carousel in one of my AngularJS application. For that I have created directive as follows:

  myApp.directive('slickSlider',function(){
   return {
     restrict: 'A',
     link: function(scope,element,attrs) {
       $(element).slick(scope.$eval(attrs.slickSlider));
   }
  }
 }); 

Here is my code in view file:

  <div class="clearfix"  
  slick-slider="{dots: false, arrows: true, draggable: 
  false, slidesToShow:3, infinite:false}">
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
              <div class="my-slide">
                  <a><img ng-src="assets/img/img1.png"/></a>
              </div>
    </div>

In this case it is working fine and initializing properly.

But when I creates slides dynamically using ngRepeat, it is not initializing and shows slides one after the other.

Here is my code using ngRepeat

<div class="clearfix"  
  slick-slider="{dots: false, arrows: true, draggable: 
  false, slidesToShow:3, infinite:false}">
      <div class="my-slide" ng-repeat="slide in slides">
         <a><img ng-src="assets/img/{{slide.img}}"/></a>
       </div>
 </div>

Any suggestion, how can I resolve it?

Karmen answered 2/7, 2014 at 5:18 Comment(1)
Note there is an AnguarJS plugin ui-carousel that does a slick carousel without jQuery.Singlebreasted
Z
20

I suspect that the slick plugin may need the DOM to be fully rendered to work properly.

Try:

myApp.directive('slickSlider',function($timeout){
 return {
   restrict: 'A',
   link: function(scope,element,attrs) {
     $timeout(function() {
         $(element).slick(scope.$eval(attrs.slickSlider));
     });
   }
 }
}); 
Zhang answered 2/7, 2014 at 5:27 Comment(4)
Just wanted to confirm, if we don't specify delay parameter in $timeout function, does that ensure that it will execute after DOM is loaded?Karmen
Yes, execution of the function is deferred until after the render phase.Zhang
If you look at the source code for $timeout, it calls $browser.defer underneath. The defer method will enqueue execution until after DOM is rendered. Unfortunately, this fact is not documented too well. You can find an interesting discussion about it here from the Angular team: github.com/angular/angular.js/issues/734. .Zhang
Buddy.. take the angular implementation... github.com/vasyabigi/angular-slickVento
R
11

$timeout still didn't give the data enough time to initialise for my scenario so I modified the directive a bit more to watch for the data to have content (this could also have the effect of rebinding whenever the data changes, not just once the DOM initializes onLoad, if you change the use of isInitialized):

app.directive('slickSlider', function () {
    return {
        restrict: 'A',
        scope: {'data': '='},
        link: function (scope, element, attrs) {
            var isInitialized = false;
            scope.$watch('data', function(newVal, oldVal) {
                if (newVal.length > 0 && !isInitialized) {
                    $(element).slick(scope.$eval(attrs.slickSlider));
                    isInitialized = true;
                }
            });
        }
    }
});

This way angularJS watches for the data to be loaded and only hooks up the slick when data has length.

(btw $watch is necessary, instead of $observe, because "data" attribute doesn't use interpolation ( "{{...}}" ): Take a look at this great answer if you want to get the low-down on this.)

usage:

<div class="clearfix" data="slides" 
    slick-slider="{dots: false,
                   arrows: true,
                   draggable: false,
                   slidesToShow:3,
                   infinite:false}">
    <div class="my-slide" ng-repeat="slide in slides">
        <a><img ng-src="assets/img/{{slide.img}}"/></a>
    </div>
</div>

thanks to this so answer and this github that I got to from this so question

Return answered 10/11, 2014 at 16:55 Comment(3)
this works fine, but it throws an error, saying "newVal is undefined. any idea why?Corregidor
@Corregidor this is quite an old answer and I didn't end up using this but I can only guess you either have a typo in your declaration of the scope.$watch function or data isn't hooked up correctly. Is the new value param definitely "newVal" and have you added valid "data" to your html declaration?Return
thanks for reply, I wrapped it inside a condition " if (newVal) " and it worked fine for me.Corregidor

© 2022 - 2024 — McMap. All rights reserved.