webcloud.

Building jQuery plugins

If you use jQuery a lot it can be a good idea to package your code into plugins. In this article I’m going to explain how to build two plugins from scratch.

A jQuery plugin is simply a way to put your code into a package. It makes it easier to maintain and use in different projects. Before you read this article it's recommended that you're familiar with how jQuery works.

Basic Structure

In case you want to share your plugin with others it can be a good idea to stick to the conventions of plugin authoring. Pick a suitable name like “myPlugin” and name your file jquery.myPlugin.js. Next thing is to define a function body.

(function($) {
    $.fn.extend({
        myPlugin: function() {
        }
    });
})(jQuery);

Wrapping everything inside an anonymous function and passing jQuery into it makes sure it doesn’t conflict with other libraries that uses ‘$’ as a shorthand (Don’t worry too much about this for now).

jQuery.tabify

I’m going to call the first plugin “tabify”. The objective is to add some tabs to the following content.

<div id="someContent">
    <h2>Tab number one</h2>
    <div>
        <p>Some tab content</p>
    </div>
    <h2>Next tab</h2>
    <div>
        <p>content...</p>
    </div>
    <h2>Last tab</h2>
    <div>
        <p>Even more stuff</p>
    </div>
</div>

Inside your plugin add the following:

return this.each(function() {
    var obj = $(this);
});

An object passed through the plugin will now return a function. I also created a reference “obj” to the object currently inside the function. Add the following inside your “this.each” statement:

obj.click(function() {
    obj.css({ backgroundColor:"red"});
});

Now pass the desired object into the plugin:

$(function(){{
    $('#someContent').tabify();
});

Clicking #someContent should result in a red background. You could pass any object into the plugin. $(‘#someContent h2’) will set a red background to any “h2” within #someContent that is clicked.

Tabifying your content

Here’s the code for jquery.tabify with included comments. I’m hoping you’re fairly familiar with JavaScript / jQuery and its basic syntax.

(function($){
    $.fn.extend({ 
        tabify: function() {

            return this.each(function() {

                //Creating a reference to the object
                var obj = $(this);

                /* Create a reference for all headings and 
                it's content using .next().
                Remember to pass the object reference 
                "obj" into the identifier. */
                
                var headings = $('h2', obj);
                var tabContent = headings.next();

                //We wan't to hide the headings and the content
                headings.hide();
                tabContent.hide();
                /* But we want to show content of the first 
                tab since it's selected by default. */
                tabContent.eq(0).show();

                //Prepend the object with the tab container (ul).
                obj.prepend('<ul class="tabs"><\/ul>');

                //For every heading create an item (<li>)
                headings.each(function() {
                    
                    var label = $(this).text();
                    $("ul.tabs", obj).append("<li>" + label + "</li>");
                });
                var tabs = $("ul.tabs li", obj);

                //And add .sel class to first item
                tabs.eq(0).addClass("sel");

                //Create a reference to the tabs for each obj
                var tabs = $("ul.tabs li", obj);

                tabs.click(function() {

                    //When a tab is clicked "de-activate" the old one
                    tabs.removeClass("sel");
                    tabContent.hide();
                    $(this).addClass("sel");

                    //And display the clicked tab
                    var current = tabs.index($(this));
                    tabContent.eq(current).show();
                });
            });
        }
    });
})(jQuery);

You will also need some CSS to actually make your <ul> look like tabs.

jQuery.tabify Demo

Tab number one

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Next tab

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Last tab

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Modularity

Now we have a nice unobtrusive jQuery plugin ready for usage. However it does have a few drawbacks.

  • It’s not flexible at all. It’s requires using “h2” in the markup. What if someone wanted to use an “h3” or “h4” they’d have to hack the plugin? (Yes I know there is a :header filter but let’s pretend there isn’t :P )
  • The tabs will always have the class “tabs”. What if there is already a “tabs” class in use on a client page?

So what can we do about this? It’s actually very simple. We can let our plugin be customizable from the outside by using the jQuery.extend method. This is what we will do in our next plugin.

jQuery.lessMore

This plugin will have a more flexible design. Our goal is to be able to hide any given number of child elements from a given parent. We build the plugin body like before but this time we pass the “options” variable into the plugin function.

(function($) {
    $.fn.extend({
        lessMore: function(options) {
        }
    });
})(jQuery);

Now we can start with adding a set of default options to the plugin

var defaults = {
    limit: 3,
    moreText: "More",
    lessText: "Less",
    numbers: true,
    append: true,
    moreClass: "more",
    lessClass: "less"   
};
var options = $.extend(defaults, options);

And by using extend method a user can now override the defaults when initializing the plugin.

$('#content').lessMore({
    limit: 5,
    numbers: false
});

Notice I chose only to override two of the defaults here. Some more code: lessMore Again I won’t go into details here but this plugin simply illustrates the use of user defined options and plugin defaults.

(function($){
    $.fn.extend({
        lessMore: function(options) {

            var defaults = {
                limit: 3,
                moreText: "More",
                lessText: "Less",
                numbers: true,
                append: true,
                moreClass: "more",
                lessClass: "less"
            };

            var options = $.extend(defaults, options);

            return this.each(function() {

                var obj = $(this);

                //Create references to the options
                var moreClass = options.moreClass
                var lessClass = options.lessClass
                var lessText = options.lessText;
                var moreText = options.moreText;

                //Calculate number of rows and hide them
                var rows = obj.children();
                var quantity = rows.length - options.limit;
                rows.slice(options.limit).hide();

                //If "numbers" is set to true append with number of items hidden
                if(options.numbers) {
                    moreText += ' (' + quantity + ')';
                }

                //Only add the link if quantity of child elements exceeds the options.limit
                if(quantity > 0) {
                    var control = '<span class="'+ moreClass +'">'+ moreText +'<\/span>';
                }

                //Check if "append" is set to true, otherwise prepend the "control"
                if(options.append) {
                    obj.append(control);
                }
                else {
                    obj.prepend(control);
                }

                //Create a reference to the control

                var itemControl = $('.' + moreClass, obj);

                itemControl.click(function() {

                    var link = $(this);
                    var linkif = link.hasClass(moreClass);

                    // If rows are hidden, show them, and change our link.

                    if (linkif) {
                        link.removeClass(moreClass);
                        link.addClass(lessClass);
                        link.html(lessText);
                        rows.slice(options.limit).show();
                    }
                    else {
                        link.removeClass(lessClass);
                        link.addClass(moreClass);
                        link.html(moreText);
                        rows.slice(options.limit).hide();
                    }	
                });
            });
        }
    });
})(jQuery);

jQuery.lessMore Demo

item 1
item 2
item 3
item 4
item 5
item 6
item 7
item 8
item 9
item 10
item 11
item 12

Hopefully you now know the basics of building a simple jQuery plugin. Here are some other articles covering the subject further, that I very much recommend reading: