Writing solid and extensible jQuery plugins
Personally, I don’t like the way jQuery encourages you to write plugins, as it’s easy to end up with a large spaghetti plate.
Despite the fact that I am a Python geek and Python is about doing things neatly and quickly with no more than one namespace - just kidding - I still like classes, instances, interfaces, utilities and adapters - this may be due to the fact that for the past 7 years I’ve worked mainly with Zope and Zope Components.
Thus, after 4 years of adding life to my work by using JavaScript I’m ready to show you a very powerful way of writing JavaScript code and hence, jQuery plugins.
First of all let me share with you the following statement from The Zen of Python, by Tim Peters:
Namespaces are one honking great idea – let’s do more of those!
Why not also apply this when writing JavaScript code? Here is how we start: we define our top namespace, safely, in order to allow it to be extended later outside this JS file:
if(!window.Alien){
var Alien = {"version": "1.0"};
}
At this point, we begin to add our plugins:
Alien.Ship = function(context, options){
var self = this;
self.context = context;
self.settings = {
width: 800,
height: 600
};
if(options){
jQuery.extend(self.settings, options);
}
self.initialize();
};
Now that we’ve added our constructor, let’s make it possible to instantiate it with the new JS keyword:
Alien.Ship.prototype = {
initialize: function(){
var self = this;
// Bind some events
self.context.bind('width-changed', function(evt, data){
self.handle_width(data);
});
self.context.bind('height-changed', function(evt, data){
self.handle_height(data);
});
// Do some initialization
self.context.css('background-color', 'gray');
},
handle_width: function(data){
var self = this;
self.settings.width = data.width;
},
handle_height: function(data){
var self = this;
self.settings.height = data.height;
}
};
OK, but where is the jQuery plugin? Well, here it is:
jQuery.fn.AlienShip = function(options){
return this.each(function(){
var context = jQuery(this);
var ship = new Alien.Ship(context, options);
context.data('AlienShip', ship);
});
};
By using this, we have the power of a jQuery plugin mixed with the flexibility of the prototype object from JavaScript.
It’s easy to call it:
jQuery('.car').AlienShip({width: 1024, height: 800});
It easy to access it:
jQuery('.car').data('AlienShip').settings.width;
And it’s easy to extend it:
Alien.Ship.prototype.handle_width = function(data){
var self = this;
self.settings.width = data.width / 2;
};
Download the full javascript file from Github