Creating a Slide Show Plugin With AngularJS
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.