The Evolution of a jQuery Plugin

By Dave McDermid

Like most people, you’ve probably already stumbled across jQuery, it seems to be quite popular these days. Maybe you’ve used it to progressively enhance a site with a little animation, maybe to stylise some content, maybe to make life with AJAX more convenient. In this tutorial I’m gonna take you through the development life cycle of a simple jQuery function, from quick hack to classy plugin. If you’ve never touched jQuery before or have a fear of Javascript, not to worry! I’ll try and keep things simple.

So why would you bother? Firstly, maintainability. The goal is to keep the mechanics of your code separated from your HTML. By removing these dependencies you can re-craft your HTML without making huge changes to your functions. Secondly, re-usability. By abstracting the function you are trying to perform away from the specifics of the site you’re currently working on, you can easily apply your code to future projects with little effort.

So, here is our quick-hack. All we want to do is create a sideways slide-out menu. Click on our button and out it slides.

//This function will run when the document has loaded
$(function() {
  //This makes our slide-out div invisible to the human eye (we can only see things 1px and wider)
  $('#divToSlideOut').css({ width: '0px', overflow: 'hidden' });
  //When we click on our button, out she slides!
  $('#divThatIClickOn').click(function() {
    $('#divToSlideOut').animate({ width: '100px' }, 300);
  });
}

Ok, still with me? Excellent. What we’ve done here is animate our slide-out div from 0 pixels wide to 100 pixels wide in 300 milliseconds. Pretty smooth. Now let’s list the things that are wrong here.

  1. This will only work with the 2 divs specified, we can’t easily apply this to any other divs.
  2. We have hard coded the width of the div, rather than letting the CSS handle layout.
  3. We have no way of re-binding the click event in case we make changes to the document, such as we often like to do with AJAX.
  4. If we place all our Javascript inside our document load function, we’ll eventually end up with one huge function, very difficult to manage.
  5. We’re pros, we wanna take it to the next level.

Right, the first thing we do is place our code in its own function. This is easy enough.

$(function() {
  makeOurSlideyMenu('#divToSlideOut', '#divThatIClickOn', 300);
}
function makeOurSlideyMenu(trigger, menu, speed) {
  $(menu).css({ width: '0px', overflow: 'hidden' });
  $(trigger).click(function() {
    $(menu).animate({ width: '100px' }, speed);
  });
}

This is great, we can now turn any pair of elements into a slide-out menu and at any speed. Great start, and already several benefits. Where do we go from here? Let’s tackle the width issue. Browsers let us add custom data to any element on our page, and jQuery provides handy methods for us to achieve this.

$(selector).data(name, value); // assign a value to our element
var value = $(selector).data(name); // get that value back

And here is our new function:

function makeOurSlideyMenu(trigger, menu, speed) {
//Remeber the normal width for our menu
  $(menu).data('oldwidth', $(menu).css('width'));
  $(menu).css({ width: '0px', overflow: 'hidden' });
  $(trigger).click(function() {
    $(menu).animate({ width: $(menu).data('oldwidth') }, speed);
  });
}

That wasn’t so bad, this is also how built-in jQuery functions like slideUp and slideDown remember the original sizes of stuff that you ask it to animate.

What we have so far is good, and there’s nothing wrong with leaving it there. However, we’re now gonna make this a full-blown jQuery plugin. What we want to be able to do is make anything we like slide-out whenever we like. This separates our sliding logic from our menu setup logic. Here’s what we want our makeOurSlideyMenu function to look like.

function makeOurSlideyMenu(trigger, menu, speed) {
  $(menu).hide();
  $(trigger).click(function() {
    $(menu).slideOut(300);
  });
}

That’s a beauty, clean and simple with no animation logic included. However, it doesn’t work yet. We now need to create a slideOut function, so this is where we get clever. jQuery lets us extend the jQuery object itself and add custom functions using the jQuery.fn.extend method. There are just a couple of simple rules to remember, we wouldn’t want to break convention now. As a rule, jQuery() functions return a jQuery object. In the cases of animation we’ll return the same object that was given to us, which allows for function chaining (y’know, like $(something).doThis().doThat() etc). Also, we try not to assume that the user will always send parameters into a function (so, if they forget to give you a speed, just assume a default speed). Inside a jQuery function, ‘this’ refers to the jQuery object containing the elements we care about.

So, let’s get stuck in:

jQuery.fn.extend({
    slideOut : function() {
    //execute on each item in the jQuery collection, returning the same collection.
    return this.each(function(speed) {
      $(this).data(‘oldwidth’, $(this).css(‘width’))
      .css({width: ’0px’})
      //animate with a default width of 500ms
      .animate({ width: $(this).data(‘oldwidth’) }, (speed ? speed : 500));
    });
  }
});

What we’ve done here is called a function within jQuery that extends the jQuery functionality. We pass into this the name of our function and its definition. We can now call our slideOut function on any jQuery collection of elements and each one will animate over the specified time. This will really make our life easier in the future and keeps the site specific logic tidy.

Dave McDermid

The Evolution of a jQuery Plugin

Dave is a web developer based in Southampton. He works for Headscape. In his spare time he enjoys photographing things, listening to music and travelling to cool places.