Adding custom method calls to the jQuery Rambling Slider

November 12, 2011


This post was originally published in the Rambling Labs Blog on November 12, 2011.


The jQuery Rambling Slider v0.1.2 was released a couple of days ago. One of the features added was the ability to start and stop the slider like this:

$('#slider').ramblingSlider('stop');
$('#slider').ramblingSlider('start');

Every serious jQuery plugin has some way to change it’s behaviour or query some data after initialized and the general approach for this is calling the custom methods as showed above.

It is well known that in order to do this, you have to perform some dynamic method calling magic. This is what you find in the jQuery documentation:

(function($){
  var methods = {
    init : function(options) { /*...*/ },
    show : function() { /*...*/ },
    hide : function( ) { /*...*/ },
    update : function(content) { /*...*/ },
  };

  $.fn.tooltip = function(method) {
    // Method calling logic
    if (methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call( arguments, 1 ));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist on jQuery.tooltip');
    }
  };
})(jQuery);

And this is the way I implemented it:

(($) ->

  publicMethods = ['stop', 'start', 'option', 'effect']

  $.fn.ramblingSlider = (options, others...) ->
    methodExists = options in publicMethods
    optionsIsString = (typeof options) is 'string'
    ramblingSlider = @data 'rambling:slider'
    isCallingGetter = (others) -> not others.length or (others.length is 1 and typeof(others[0]) is 'string')

    if ramblingSlider
      return if methodExists
        value = ramblingSlider[options](others...)
        if isCallingGetter others
          value
        else
          @
      else
        if optionsIsString
          $.error "Method '#{options}' not found."
        else
          $.error "Slider already initialized." if options
    else
      return $.error "Tried to call method '#{options}' on element without slider." if methodExists or optionsIsString

    @each (key, value) ->
      element = $ @
      return if element.data 'rambling:slider'

      ramblingSlider = new RamblingSlider @, options
      element.data 'rambling:slider', ramblingSlider

      ramblingSlider.initialize()
      ramblingSlider.run()

  RamblingSlider = (element, options) ->
    ###
# Method definitions
###
)(jQuery)

Kind of cumbersome if you ask me, but hey, it works :P. The cool stuff is that I added the option and effect methods, as well as identifying if it’s a setting or getting the value. This is great because I can have kind of private setters and public getters:

//Stop and start are really setters
$('#slider').ramblingSlider('stop'); // => [div#slider] for method chaining
$('#slider').ramblingSlider('start'); // => [div#slider] for method chaining
$('#slider').ramblingSlider('effect'); // => 'random'
$('#slider').ramblingSlider('option'); // => Object with all options
$('#slider').ramblingSlider('option', 'speed'); // => 400
$('#slider').ramblingSlider('effect', 'boxRain'); // => [div#slider] for method chaining
$('#slider').ramblingSlider('option', 'speed', 600); // => [div#slider] for method chaining
$('#slider').ramblingSlider('option', 'startSlide'); // => 0
$('#slider').ramblingSlider('option', 'startSlide', 2); // => throws error "Slider already running. Option 'startSlide' cannot be changed."

Note that the option slideStart can only be passed when initializing, so it becomes a readonly option after initialized.

Cool huh?