A more generalized jQuery plugin with CoffeeScript

Few days ago I was prototyping some jQuery for a website and I decided to make a plugin out of it. To add some more fun to the experience, I wanted to do it with the newly discovered CoffeeScript.

A quick search shows how to implement a basic jQuery plugin in coffeescript. What I wanted though, was more like a reusable pattern like the one described as “perfect jQuery plugin” by Jupiter24.

To start you’ll of course need to setup coffeescript. It requires Node.js and npm. If you’re on a Mac you may want to use Homebrew to setup node.js in the first place. Additionally, there is a TextMate bundle for coffeescript if you happen to use that text editor.

The goal

What I want to achieve is to write a class in coffeescript and have it accessible via jQuery as a plugin. Note that this plugin will be accessible from javascript as any other and applicable with $("#myDiv").myPlugin({ /*options*/ }).

As suggested by the official jQuery plugin authoring guide, methods of our plugin class will be accessible as $("#myDiv") .myPlugin("methodName");.

The coffeescript class I want to write should look like:

class myPlugin
  # the name of the class should also become the plugin name

  constructor: (@element, @options) ->
    # element will be a jQuery element and options the user options

  methodName: () ->
    # will do something when invoked from jQuery as $('.somehting').myPlugin("methodName")

Plugin abstract class

Here is the abstract class that will do all the magic for us. This class will take care of installing a jQuery plugin and let us access the @element and @options from out instance.

# Getting a familiar reference to jQuery
$ = jQuery

# An abstract class that provide jQuery plugin setup functionalities.
class jQueryPlugIn

  # Redefine this dictionary to specify default options
  @defaultOptions: {}

  # The default constructor calls the initialize method and set the jQuery element.
  # Remember to call super in subclasses if you want to maintain this behaviour.
  constructor: (@element, options) ->
    @initialize options

  # Method to initialize the plugin instance with the given options
  # This method could be called
  initialize: (@options) ->

  # Install a class as a jQuery plugin. Assuming that myClass extends jQueryPlugIn it can than be installed with:
  # myClass.installAsjQueryPlugIn()
  @installAsjQueryPlugIn: (pluginName = @name) ->
    pluginClass = @
    $.fn[pluginName] = (options, args...) ->
      options = $.extend pluginClass.defaultOptions, options or {} if $.type(options) is "object"
      return @each () ->
        $this = $(this)
        instance = $this.data pluginName
        if instance?
          if $.type(options) is "string"
            instance[options].apply instance, args
          else if instance.initialize?
            instance.initialize.apply instance, [options].concat args
        else
          plugin = new pluginClass $this, options, args...
          $this.data pluginName, plugin
          $this.addClass pluginName
          $this.bind "destroyed.#{pluginName}", () ->
            $this.removeData pluginName
            $this.removeClass pluginName
            $this.unbind pluginName
            plugin.destructor()
          plugin

It is quite dense, but here it is the breakdown of the core method, installAsjQueryPlugIn:

  • The class method has only one parameter (pluginName = @name) that will make the plugin have the same name as the class by default;
  • PluginClass will hold a reference to the actual class of our plugin;
  • When installing the plugin to jQuery.fn we extend the user provided options with the default ones;
  • On every selected DOM element to which apply the plugin, we get a reference to the corresponding jQuery element and try to get the instance of a previously created plugin;
  • If we get that instance, we can either call a method or re-initialize it with different options;
  • If no instances has been found, we create one and save it as data on the jQuery element;
  • We then add some more informations to the element, a class named as the plugin and a bind to the destroyed event (called by jQuery when an element gets removed) that will clear what we added and call the destructor.

Conclusions

A quick example on how to use the class, derived from Juppiter24′s original, is available at jsFiddle. Using CoffeeScript can enhance jQuery usage by a good amount.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>