Creating a Slide Show Plugin With AngularJS

Sandeep Panda
Share

Gone are the days when you used to write hundreds of lines of jQuery to create a custom image slider! It’s time to go Angular and achieve the same goal with smaller, simpler code. This tutorial will show how to create a slide show plugin with AngularJS. We will use Angular directives and animations to achieve this. If you are not familiar with directives, be sure to read my AngularJS directive series. Another nice thing about this approach is that, we are not going to write a single line of jQuery! How cool is that? So, let’s get started.

Step 1: Creating the AngularJS Directive

When it comes to AngularJS it’s all about architecting the app first and then using the appropriate markup/design. Since we want our slider to be self contained and easily plugged into an existing AngularJS app, creating a directive is the correct way to go. So, let’s get started with an empty directive named slider:

var sliderApp = angular.module('sliderApp', []);

sliderApp.directive('slider', function($timeout) {
  return {
    restrict: 'AE',
    replace: true,
    scope: {
      images: '='
    },
    link: function(scope, elem, attrs) {},
    templateUrl: 'templates/templateurl.html'
  };
});

The important thing to note is that we have isolated the scope of our directive. Since we will need several functions/properties only for the internal usage, we’ve chosen to create an isolated scope instead of polluting the parent scope. Also we should be able to accept a list of images from the parent scope for displaying. That’s why we are using a = binding. Finally, the template for the directive goes inside the templateurl.html file.

Step 2: Set Up the Controller to Supply Images

Next, let’s create a controller that creates an array of five image objects in its scope. We will pass these images to the directive later.

sliderApp.controller('SliderController', function($scope) {
  $scope.images = [{
    src: 'img1.png',
    title: 'Pic 1'
  }, {
    src: 'img2.jpg',
    title: 'Pic 2'
  }, {
    src: 'img3.jpg',
    title: 'Pic 3'
  }, {
    src: 'img4.png',
    title: 'Pic 4'
  }, {
    src: 'img5.png',
    title: 'Pic 5'
  }];
});

Step 3: Write the Directive Markup

Now let’s return to our directive and produce the markup. Since the directive needs to render each image in the array, we will use ng-repeat. Also we will have two buttons: prev and next to navigate the images. The content of templates/templateurl.html is shown below.

<div class="slider">
  <div class="slide" ng-repeat="image in images" ng-show="image.visible">
    <img ng-src="img/{{image.src}}" />
  </div>
  <div class="arrows">
    <a href="#" ng-click="prev()">
      <img src="img/left-arrow.png" />
    </a>
    <a href="#" ng-click="next()">
      <img src="img/right-arrow.png" />
    </a>
  </div>
</div>

The markup is pretty simple. The src property of the image points to the image location. The image.visible property indicates if the image is visible. When we move forward/backward to the next image, we need to set the visible property of that particular image to true. The rest of the image objects should have this property set to false. We have also passed the next() and prev() functions to ng-click so as to perform navigation. The image.title property is important in case you want to display the description for each image.

Step 4: Update the Directive

We need to keep track of the currently visible image. For this we will use a property called currentIndex in the directive’s isolated scope. We also have the next() function which increments currentIndex and prev() function which decrements it. Let’s update the link function of the directive with the following code:

scope.currentIndex = 0; // Initially the index is at the first image

scope.next = function() {
  scope.currentIndex < scope.images.length - 1 ? scope.currentIndex++ : scope.currentIndex = 0;
};

scope.prev = function() {
  scope.currentIndex > 0 ? scope.currentIndex-- : scope.currentIndex = scope.images.length - 1;
};

This just increments/decrements the currentIndex based on the arrow button (next/prev) click. But, we need to detect when this change occurs and appropriately make the image at currentIndex visible by setting the visible property to true. As we have already passed image.visible to the ng-show directive in our HTML markup, any change in this property will automatically show/hide the images. We should also watch the directive scope for changes to currentIndex. Append the following code to the end of the previous code snippet:

scope.$watch('currentIndex', function() {
  scope.images.forEach(function(image) {
    image.visible = false; // make every image invisible
  });

  scope.images[scope.currentIndex].visible = true; // make the current image visible
});

Step 5: Animate the Slider

Angular 1.2 introduced a new animation framework that can be used to associate CSS3 animations with various events seamlessly. You just need to specify the animation and Angular takes care of the rest. For example, when an element is being hidden Angular will automatically add classes like ng-hide-add and ng-hide-active. You can write CSS against these classes to perform the desired animations. Angular animation is beyond the scope of this tutorial. However, I encourage you to go through this resource to learn about animations. To add animations, update the module like this:

var sliderApp = angular.module('sliderApp', ['ngAnimate']);

And include the following script in the HTML after the Angular script:

<script src="http://code.angularjs.org/1.2.9/angular-animate.min.js"></script>

Next, add the following CSS rules to describe the transitions:

.slide.ng-hide-add,
.slide.ng-hide-remove {
  -webkit-transition: all linear 0.5s;
  -moz-transition: all linear 0.5s;
  -o-transition: all linear 0.5s;
  transition: all linear 0.5s;
  display: block!important;
}
.slide.ng-hide-add.ng-hide-add-active,
.slide.ng-hide-remove {
  opacity: 0;
}
.slide.ng-hide-add,
.slide.ng-hide-remove.ng-hide-remove-active {
  opacity: 1;
}

Step 6: Use the Directive

Now it’s time to use the directive in HTML. While using the directive we also need to pass the images array declared in the controller scope to the directive.

<body ng-controller="SliderController">
  <h1>Slider Using AngularJS</h1>
  <slider images="images" />
</body>

That’s all! Our brand new Angular slider is ready. For styling purposes, we can include the following CSS:

* {
  font-family: 'Open Sans', sans-serif;
}
.center-grey {
  background: #f2f2f2;
}
.slider {
  position: relative;
  padding: 5px;
  width: 610px;
  margin: auto;
  margin-top: 40px;
}
.slide {
  position: absolute;
  top: 0;
  left: 0;
  box-shadow: 0px 0px 15px #999;
}
.arrows {
  position: absolute;
  top: 10px;
  right: 20px;
}
.arrows img {
  height: 32px;
}
h1 {
  text-align: center;
  padding: 10px;
  font-size: 40px;
  color: #222;
}

Bonus

In addition to responding to the next/prev clicks we might also want our slider to automatically slide to the next image after an interval. To do that we can use Angular’s $timeout service. Modify the directive as shown below to declare a dependency on $timeout:

sliderApp.directive('slider', function($timeout) {
  ...
  // configuarations here
});

And append the following snippet to the link function which calls the next() function every five seconds:

var timer;
var sliderFunc = function() {
  timer = $timeout(function() {
    scope.next();
    timer = $timeout(sliderFunc, 5000);
  }, 5000);
};

sliderFunc();

scope.$on('$destroy', function() {
  $timeout.cancel(timer); // when the scope is getting destroyed, cancel the timer
});

Conclusion

We’ve reached the end of the tutorial, and we’ve learned how to create an AngularJS image slider using a directive (with a little animation). We achieved this with a minimum amount of JavaScript code and no jQuery DOM manipulation. There can be many ways to achieve the same thing in Angular and this tutorial has shown just one way. If you can think of a better method or have something to add/ask feel free to comment.

The source code for the complete app is available on GitHub for download. You can also check out a live demo of the app.