Skip to main content

Just another object-oriented approach to jQuery plugins

It has been almost a year since I have been working primarily in JavaScript. During this time I have written three jQuery plugins and loads of other scripts.This is the story of how my approach to writing jQuery plugins has evolved.

I was working on my first plugin, which was supposed to be a large (in LOC) and went through the authoring mentioned on the jQuery site. In the beginning- it was great, a few exposed methods, well organized code, private functions, everything looked pretty. Soon the code reached some 1000 lines and it started becoming messy for me. To clarify, I am basically a java developer. I accept that the coding practices will obviously differ in every language, but for me, object oriented approach to code seems much more understandable and tidier than 'functions everywhere' thing!

I began searching for object oriented approaches people take in writing jQuery plugins. There are many, but mostly at the cost of some other flexibility. Some approaches allow only one public method, claiming only one namespace is must but more control was needed in the calendar. Some allow complete public access to the options object, but additional control was needed. There were one time calculations based on options that were necessary for the required functionality. Now making the options object public won't give me that control, will it? But apart from that, I could not understand the requirement of making it fully public. Pardon me, this statement is not to question those who follow these approaches, but this is what was thought.

A better approach was needed, where all the flexibility of making it a 'functions everywhere' is retained and a little more organization is achieved in the code. So there emerged a merger. A merger that:

  • Allows multiple methods to be made available.
  • Claims only one namespace.
  • Does not make options simply public.
  • Keeps a context, maintains a state.
  • And follows every other requirement mentioned as a guideline while writing plugins by the jQuery authors.
That merger has now evolved into a simple, precise plugin template! All you need is a case-sensitive, replace-all and you are ready with a working plugin, set with the basic features ready for more, organized plugin...

Here's the code:
/**
 * Plugin comments
 */
(function($, undefined){
 var MyPlugin = function(element, options){
  
  /*
   * *************************** Variables ***************************
   */
  var defaults = {
   defaultValue : '2'
  }; //default options
  
  /*
   * *************************** Plugin Functions ***************************
   */
  
  /*
   * Initializes plugin.
   */
  function initialize(options){
   extendOptions(options);
   sl.log("Got Options- initialize: ");
   sl.log(options);
  }
  
  /*
   * Updates plugin.
   */
  function update(options){
   sl.log("Got Options- update: ");
   sl.log(options);
  }
  
  /*
   * Destroy plugin changes
   */
  function destroy(options){
   // Remove all added classes.
   // Remove all bound methods.
   
   // Remove plugin data
   element.removeData('myplugin');
  }
  
  /*
   * Updates plugin options after plugin has been initialized.
   */
  function setOptions(options){
   extendOptions(options);
  }
  
  //expose plugin functions
  this.initialize = initialize;
  this.update = update;
  this.destroy = destroy;
  this.setOptions = setOptions;
  
  /*
   * *************************** Utility Methods ***************************
   */
  /*
   * Extend the default options using the passed options.
   */
  function extendOptions(options){
   if (options) {
    $.extend(true, defaults, options);
   }
  }
 };
 
 var mP = $.myPlugin = {version: "0.01"};
 $.fn.myPlugin = function(options){
  var args = arguments; // full argument array passed to the plugin.
  
  // Available methods in plugin
  var pMethods = {
   init : function(options){
    // Get the plugin data
    if (this.data('myplugin')) return;
    // Initialize the plugin
    var myplugin = new MyPlugin(this, options);
    // Add plugin data to the element
    this.data('myplugin', myplugin);
    myplugin.initialize(options);
   },
   update : function(options){
    // Get the plugin data
    var myplugin = this.data('myplugin');
    if (!myplugin) return; // do nothing if plugin is not instantiated.

    myplugin.update(options);
   },
   destroy : function(options){
    // Get the plugin data
    var myplugin = this.data('myplugin');
    if (!myplugin) return; // do nothing if plugin is not instantiated.
    
    // destroy data and revert all plguin changes.
    myplugin.destroy(options);
   },
   setOptions : function(options){
    // Get the plugin data
    var myplugin = this.data('myplugin');
    if (!myplugin) return; // do nothing if plugin is not instantiated.
    
    // Update the plugin options
    myplugin.setOptions(options);
   }
  };
  
  // For each element, check and invoke appropriate method passing the options object
  return this.each(function(i, tElement){
   var element = $(tElement);
   
   if (pMethods[options]){
    pMethods[options].call(element, args[1]);
   } else if (typeof options === 'object' || !options){
    pMethods['init'].call(element, args[0]);
   } else {
    $.error( 'Method ' +  options + ' does not exist in jQuery.myplugin' );
   }
  });
 };
})(jQuery);

Now what you need to get going is the replace-all, this is what you replace:

MyPlugin : PluginName
myPlugin : Plugin JQuery Method Name/pluginName
myplugin : Data Name/Variable Name
mp       : pN
pMethods : pluginNameMethods
defaults : defaulsObjectName


That's it!
You are ready with a working plugin!
Oh yes, that sl there in the code is actually the SmartLogger. Read about it here.
This is a quick post and I plan to update the post with more explanation of the code, do visit again!

Let me know how you find it in the comments.

Comments

Popular posts from this blog

Using Docker and a Private Registry with VPN On Windows

Wasn’t that a very specific title? Docker has a very good documentation and reading that alone is enough for most of the straightforward tasks we might want to do. But as always some practical tasks are not straightforward, hence this blog. What we are going to see here today is how to setup docker toolbox on a Windows machine, make it work even when VPN is connected, make it talk to a private, insecure docker registry (that is why VPN) and configure it so it can run docker compose and see how we can set this config as a one-time activity. That’s quite a mouthful, but yes this is what we are going to do. All ready? Let us begin then.

Install Docker ToolboxGo and download the docker toolbox and install it. That should create a shortcut called “Docker Quickstart Terminal”. Run it. That should show you an error about virtualization.

Enable VirtualizationRestart your machine, enter the BIOS settings and enable virtualization. It may be under advanced settings. On this Laptop, it is under th…

Yet another packager for node

Yet another packager for node There are so many packaging systems for node already, or maybe not as many, so here I am presenting another way to package your applications into an self extracting executable that has no dependencies. Ah well, a few dependencies, like the processor architecture, and Linux operating system may be, but that is all. What is it? It is a modified shell script originally used to create self-extracting and installing applications for Linux platforms. What it does is, it creates a tarball which includes your code, the modules it depends on, the specific node binary it uses, and appends it to a script with the command to execute your code. It is essentially a binary merge of the files, the shell script and the tar.This is not something new, people have used such a system in the past to deliver applications for Linux, every time you see an obscenely large ‘.sh’ file (for being that, a shell file) that can install or execute an application without requiring any ot…

Redis Cluster: Fact Sheet (Not Just Issues)

Redis and the Redis clustering works very differently from the other data stores and data store clusters. The differences are not always as obvious and may come up as realizations down the line while using Redis, like what happened in our case. We are using a Redis cluster, with which, fortunately, we have not faced many issues so far. But that does not mean we will not and we shall need to be prepared.
Recently we were working on getting a Redis cluster up and working with docker compose and was enlightened to some of the differences which later led to disillusionment for me. Thought that there should be a ‘document of facts‘ on Redis and Redis cluster which people/myself can refer to. So I decided to create one, enjoy:
Redis is great as a single server. In a Redis cluster, all your masters behave as if they are simultaneously active (not sure if they all are masters at the same time technically, but they behave as such). Every master in a cluster knows every other master/node in the clu…