Rambling Labs Blog Ramblings on software development

  • Adding custom method calls to the jQuery Rambling Slider

    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?

  • blog comments powered by Disqus