Book Image

Instant jQuery Boilerplate for Plugins

By : Jonathan Fielding
Book Image

Instant jQuery Boilerplate for Plugins

By: Jonathan Fielding

Overview of this book

jQuery plugins helps you to extend jQuery's prototype object. jQuery plugins are used to achieve a specific task with a collection of elements, they are modular and reusable across several projects.Instant jQuery Boilerplate for Plugins is a hands on guide to writing your own plugins. The recipes in this book will guide you through the steps of plug-in development.Each recipe is a short tutorial within itself that will help you explore different options available within jQuery by providing a clear explanation on what jQuery Boilerplate has to offer. By the end of the book, you will have learned how to write a plugin and will be ready to start writing plugins of your own.
Table of Contents (7 chapters)

Writing a carousel with jQuery Boilerplate (Intermediate)


Carousels are very common across many websites, and being a web developer, it is essential you know how to code one.

Getting Ready

Before you get started with your carousel, you will need to find yourself five images of the same size to be your carousel content. These can be anything, from simple images numbered 1 to 5 (as I will be using) to photos of friends or family.

We will once again use the template that we previously set up.

How to do it...

  1. We will start by setting up the HTML for our carousel. This will simply consist of an unordered list within a carousel div wrapper. Each of the list items is populated with the images that you have selected to use inside your carousel:

    <div class="carousel">
      <ul>
        <li><img src="images/item1.jpg" alt="" /></li>
        <li><img src="images/item2.jpg" alt="" /></li>
        <li><img src="images/item3.jpg" alt="" /></li>
        <li><img src="images/item4.jpg" alt="" /></li>
        <li><img src="images/item5.jpg" alt="" /></li>
      </ul>
    </div>
  2. Users without JavaScript will simply get a list of the images. Now for users with JavaScript, we are going to add the carousel's functionality to our list.

  3. The first thing we need to do is name our plugin. There are lots of plugins, so simply calling it a carousel will cause issues; so for this example, we will call our plugin boilerplatecarousel. We will need to update the pluginName variable to reflect this as follows:

    var pluginName = "boilerplatecarousel",
  4. Our next step is to look at our plugin's init method:

    1. To start with, we want to cache our element as $element; we do this by setting the $element variable equal to $(this.element).

    2. We then need to determine the width of the items and how many items we will be sliding between; the width will be achieved by using $element.find('li').width(), and the number of items will be counted using $element.find('li').length.

    3. We will then store the jQuery object for the carousel slider in this.carousel, and then add a width parameter equal to the item width multiplied by the number of items.

    4. We then need to add a controller to allow the user to interact with the carousel; this should include a next and previous button.

    5. Finally, we need to add a functionality to the buttons that we will use for the event delegation to fire the this.controller method:

      init: function() {
        var $element = $(this.element);
      
        var $items = $element.find('li');
        var width = $items.width();
        var count = $items.length;
      
        this.carousel = $element.find('ul');
      
        this.carousel.css('width',width*count);
      
        $element.append('<ul class="controller"><li><a href="#" class="prev">prev</a></li><li><a href="#" class="next">next</a></li></ul>');
      
        $element.on('click', '.controller li a', this.controller);
      
      }
  5. Once we have set up our init function, we need to add some functionality to our controller method. As we are sharing one method between both the next and previous buttons, we will need to identify which button has been clicked on in this method so that we know what the user wants to do. Before we can identify the button that has been clicked on, we need to set up some variables. First we will cache $(this) as $this, then we will read the class parameter of the button that has been clicked and store it as navClass, retrieve the plugin instance as plugin, and work out which item is currently visible to the user and cache it as currentItem. All this is shown in the following code snippet:

    controller: function(e){
      var $this = $(this),
      navClass = $this.attr('class'),
      plugin = $(e.delegateTarget).data("plugin_" + pluginName),
      $currentItem = $(plugin.element).find('li').first();
    
      if(navClass.indexOf('next') !== -1){
        $currentItem.appendTo(plugin.carousel);
      }
      else if(navClass.indexOf('prev') !== -1){
        $(plugin.carousel).prepend($(plugin.carousel).find('li').last());
      }
    
      return false;
    }
  6. At this point, we currently have the plugin reordering our items; however, it doesn't appear to look much like a carousel as all the items are still visible. To make it appear more like a carousel, we need to look at adding some styles.

  7. The first step is to define the styles for our container, which will provide a width for the view area of the carousel and will hide all those items not in the view area. We will define a width of 500px and use overflow:hidden to hide those that are outside of the view area.

    .carousel{
      overflow: hidden;
      width: 500px; 
      position: relative;
    }
  8. We then need to look at the styles of the slider. The UL tag itself will need to override the default padding on a UL tag by setting padding: 0px, and we will use overflow:hidden to clear the floats of the items inside the UL tag.

    .carousel ul{
      padding: 0px;
      overflow: hidden;
    }
  9. We will need to style the appearance of the individual items in the carousel. We need all of them to be floated in line with each other, have a width of 500px to match the view area. Additionally, we need to override the default list-style parameter and set its value to none. This is done as follows:

    .carousel ul li{
      float: left;
      width: 500px;
      list-style: none;
    }
  10. Finally, we need to add some styling to both the arrows, which will be achieved by positioning them at the top of the carousel.

    .carousel ul.controller li a.next,.carousel ul.controller li a.prev{
      position: absolute;
      top: 140px;
      background: #fff;
      padding: 20px;
    }
    
    .carousel ul.controller li a.prev{
      left: 0px;
      border-radius: 0 10px 10px 0;
    }
    
    .carousel ul.controller li a.next{
      right: 0px;
      border-radius: 10px 0 0 10px;
    }

There's more...

At this point, all our carousel is doing is reordering the elements; it is not doing any animation, as one would normally expect in a carousel. We will now add one animation; hopefully, with what you will learn here, you could go on to add your own effects:

  1. When working on this extension to the carousel, we are extending our existing carousel plugin.

  2. Our first step is to extend the defaults object literal to have an extra value for the effect; this will enable the plugin to support multiple effects if you wish.

    defaults = {
      effect: "none"
    };
  3. We then need to add a new method to our Plugin prototype's object literal to handle the effect; we will name this as effect.

  4. Our first step is to move our existing transition with no effect to the effect method, and for this, we will need to write the first part of our effect method. To begin with, we will move the if statement we previously had in our controller method to the effect method.

    effect: function($currentItem, direction){
      if(direction === "next"){
        $currentItem.appendTo(this.carousel);
      }
      else if(direction === "prev"){
        $(this.carousel).prepend($(this.carousel).find('li').last());
      }
    }
  5. We then need to make some changes to our controller method so that it uses the new effect method for the transition. Where we previously had an if statement for the transition, we now have an if statement that will fire the effect method with the correct parameters, shown as follows:

    controller: function(e){
      var $this = $(this),
      navClass = $this.attr('class'),
      plugin = $(e.delegateTarget).data("plugin_" + pluginName),
      $currentItem = $(plugin.element).find('li').first();
    
      if(navClass.indexOf('next') !== -1){
        plugin.effect($currentItem, "next");
      }
      else if(navClass.indexOf('prev') !== -1){
        plugin.effect($currentItem, "prev");
      }
    
      return false;
    }
  6. At this point, our carousel should work in the same way as before, cycling through each of the items in the carousel one-by-one with no animation. Now, we can extend our effects method to provide extra transitions. The first step is to create an if statement that selects which effect should be used. The idea is that, if the developer using the plugin has not indicated which effect they want, it will resort to the default no effect.

    effect: function($currentItem, direction){
      var itemWidth = $currentItem.width();
    
      if(this.options.effect === "slide"){
        //slide effect will go here
      }
      else if(this.options.effect === "none"){
        if(direction === "next"){
          $currentItem.appendTo(this.carousel);
        }
        else if(direction === "prev"){
          $(this.carousel).prepend($(this.carousel).find('li').last());
        }
      }
    }
  7. Once we are happy with our if statement, we can start working on our slide effect. For the effect to work, we need to animate the sliding of the UL containing the carousel's items to the left and right. The view area of the carousel is only set to the width of one item, so moving the UL tag within this will show our desired animation.

  8. As per the no animation effect, we first need to add a simple if statement that reads the direction parameter of the effect method and allows us to handle both directions.

    effect: function($currentItem, direction){
      var itemWidth = $currentItem.width();
    
      if(this.options.effect === "slide"){
        if(direction === "next"){
        }
        else if(direction === "prev"){          
        }
      }
      else if(this.options.effect === "none"){
        if(direction === "next"){
          $currentItem.appendTo(this.carousel);
        }
        else if(direction === "prev"){
          $(this.carousel).prepend($(this.carousel).find('li').last());
        }
      }
    }
  9. Once we have the if statement, we are able to start working on our logic inside it. Our first step is to work on the code required for when our first condition is met, which is when the direction variable is equal to next.

  10. For this, we are going to use the jQuery.animate() function to animate the shifting of the UL containing the items on the left. The distance travelled will equal the width of one of the carousel items. As the complete function parameter, we move the item to the end of the list of items and then reset the left value to 0px.

    effect: function($currentItem, direction){
      var itemWidth = $currentItem.width();
    
      if(this.options.effect === "slide"){
        if(direction === "next"){
          $(this.carousel).animate({
            left: "-="+itemWidth
          }, 500, function() {
               $(this).find('li').first().appendTo(this);
               $(this).css('left','0px');
             });
        }
        else if(direction === "prev"){
    
        }
      }
      else if(this.options.effect === "none"){
        if(direction === "next"){
          $currentItem.appendTo(this.carousel);
        }
    
        else if(direction === "prev"){
          $(this.carousel).prepend($(this.carousel).find('li').last());
        }
      }
    }
  11. Moving to the previous direction is not as simple. Firstly, we need to move the last carousel item to the beginning of the UL tag containing the items; then we need to set the position of the UL so that the current item is still visible. Finally, we need to use the jQuery.animate() function to move to the previous item. The main problem with this is that this function does not allow us to provide it with functionality before the animation. Along with this, we need to ensure that, if the user clicks on the previous button X times, then we need to move an X number of items. This means we need to look at how we can manipulate the animation queue. jQuery provides us with a way to do this using .queue(). In its simplest form, we only need to provide one parameter, which is our method that we wish to queue. This will add the method to be called as part of the fx queue.

    effect: function($currentItem, direction){
      var itemWidth = $currentItem.width();
    
      if(this.options.effect === "slide"){
        if(direction === "next"){
          $(this.carousel).animate({
            left: "-="+itemWidth
            }, 500, function() {
              $(this).find('li').first().appendTo(this);
              $(this).css('left','0px');
              });
          }
        else if(direction === "prev"){
          $(this.carousel).queue(function () { });
        }
      }
      else if(this.options.effect === "none"){
        if(direction === "next"){
          $currentItem.appendTo(this.carousel);
        }
        else if(direction === "prev"){
          $(this.carousel).prepend($(this.carousel).find('li').last());
        }
      }
    }
  12. Now when we click on the previous button, we will be adding a new item to the fx queue. Next, though, we need to add the functionality that we previously discussed to the queue. (Rather than repeating the code, we will now only show the queue). The first thing we need to do is create a variable in which we will store the queue; we will call this currentQueue and will set the value to null. We then need to move the last item to the beginning of the list and set the left position of the UL item list to be 0 minus the width of 1 item.

    $(this.carousel).queue(function () {
      var currentQueue = null;
    
      $(this).prepend($(this).find('li').last());
      $(this).css('left',-itemWidth);
    });
  13. We can then look at adding our animation. We do this in the same way we used the jQuery.animate() function previously; however, this time we are moving the UL item container in a positive direction. We will also not find the need to pass a callback method as, once the animation is complete, the items will be in the correct place. The code snippet to do this is as follows:

    $(this.carousel).queue(function () {
      var currentQueue = null,
      var $this = $(this);
    
      $this.prepend($(this).find('li').last());
      $this.css('left',-itemWidth);
    
      $this.animate({
        left: "+="+itemWidth
      }, 500)
    });
  14. We have added our animation to the queue using .animate(); however, this will add it to the end of the queue; if the user has clicked on the button multiple times, the animation will be a bit strange. Thus, we now need to re-sort the order of the fx queue so that it flows correctly. To start with, we will now use the currentQueue variable we declared earlier to store our queue, which can be retrieved using $(this).queue(). We then need to move the last item of the array to be the second item in the array (so that it is fired next). We do this by using .splice() with the index of 1, howMany set to 0 (so that we do not remove any items) and we pass the last element of the array as the value to add into the array. We can then simply use .pop() to remove the last item from the queue as we have already moved it to the new position. We then need to update the fx queue array with the values of the updated queue that we have manipulated.

    $(this.carousel).queue(function () {
      var currentQueue = $(this).queue(),
      var $this = $(this);
    
      $this.prepend($(this).find('li').last());
      $this.css('left',-itemWidth);
    
      $this.animate({
        left: "+="+itemWidth
      }, 500);
    
      currentQueue = $(this).queue();
    
      currentQueue.splice(1, 0, currentQueue[currentQueue.length-1]);
      currentQueue.pop();
    
      $(this).queue(currentQueue);
    });
  15. Finally we need to add $(this).dequeue() at the end of the method, which will then remove this function from the queue and trigger the next item to be fired. As we just made our next item to be animation, our animation item will now trigger.

    $(this.carousel).queue(function () {
      var currentQueue = null;
    
      $(this).prepend($(this).find('li').last());
      $(this).css('left',-itemWidth);
    
      $(this).animate({
        left: "+="+itemWidth
      }, 500);
    
      currentQueue = $(this).queue();
    
      currentQueue.splice(1, 0, currentQueue[currentQueue.length-1]);
      currentQueue.pop();
    
      $(this).queue(currentQueue);
    
      $(this).dequeue();
    });
  16. Now that we have finished this, our previous button should work, so try clicking on it. You should find that you're able to click on it multiple times with the animation remaining smooth.