Friday, December 24, 2010

Creating complete jQuery plugin

Introduction

jQuery promote writing reusable components as jQuery plugins. This is good practice and a smart way of working. Also jQuery promotes a certain style for writing these plugins. This short example is simple guideline that show how to do this.

Example

You can download simple example (that include complete Java web application and jQuery plugin that uses Ajax) from my google code repository.

This example is composed of single JSP page that show programming languages names and by clicking on some language we get description of that language in the bottom of page by pulling it from server using Ajax.


1.Naming conventions.

The recommendation is simple: prefix the file name with jQuery, then follow that with the name of the plugin, optionally include version number of the plugin, conclude it with .js.

We named our plugin "details" (because it show details about some programming language, I know it's stupid...but what can you do! :) ) and we named file jquery.cwp.details.js. Here we added unique plugin name to our self (cwp stands for "coding with passion") and limiting name conflict problems.

Similar consideration need to be taken with the names we give to our function. In our case we did not bother with that because there is 100% chance that this plugin will be used by me and only me and I probably will never use it again (outside of this example)...so there you go.

2.Handle $ alias properly.

We have no way of knowing weather a web developer (using out plugin) use $.noConfilct() function to allow the $ to be used by another library, so we need to guard ourself for such situation. We can use following trick to do so:

(function($) {
  //plugin impl.
  })(jQuery);

By passing jQuery to a function that defines the parameters as $, $ is guaranteed to reference jQuery within the body of the function.

3.Complex parameter list.

Most plugins tend to be simple affairs that require few, if any, parameters. Intelligent defaults are supplied when optional parameters are omitted. The bind method is a good example; it the optional parameters are omitted, the listener function, which is normally specified as the third parameter can be supplied as the second.

We can use handy $.extend function to merge default parameter with optional. Consider the following show example:

function complex(p1, options) {
  var settings = $.extend({
    option1 : defaultVal1,
    option2 : defaultVal2,
    option3 : defaultVal3
  }, options||{});
  //"meat" of the function.
}

By merging the values passed by the web developer in the options parameter with an object containing all the available options with their default values, settings variable ends up with the default values superseded by any explicit values specified by the developer.

Note: With options||{} we guard ourself against options object that is null. or undefined.

4.Wrapper methods.

The true power of jQuery in the ability to easily and quickly select and operate on DOM elements. Luckily, we can extend that power by adding wrapper methods of our own. The general pattern of doing so is:

$.fn.functionName = function(params){function-impl};

That is almost it, just remember to always return (this) for chaining support. All that said, here is our function in all its glory :) :

(function($) {
    $.fn.details = function(url, options) {
        var settings = $.extend({
            customClass: null,
            paramName: 'language',
            url: url
        }, options||{});
        this.click(function(event) {
            $('div.details').remove();
            //substitute lt with appropriate start tag and gt with end tag...
            $('lt div gt')
            .addClass('details' +
                (settings.customClass ? (' ') + settings.customClass : ''))
            .css({
                display: 'none'
            })
            .appendTo('body')
            .load(settings.url,
                encodeURIComponent(settings.paramName) + '=' +
                encodeURIComponent($(event.target).text()),
                function() {
                    $(this).closest('.details').fadeIn('slow');
                });
        })
        this.addClass('details');
        return this;
    };
})(jQuery);

No comments:

Post a Comment