Optional Options

09/12/2013, Thu
Categories: #JavaScript
Tags: #jQuery

Common Object Format

Most JQuery plugins will use the common format of customizing by providing a plain object to the plugin handler. This is well suited for plugins that provide a widget to your page where a callback might not be needed.

// Options Object for Plugin
$("#my-element").widgetLike({
  firstOption: "setHigh",
  secondOption: false,
});

Callback Format

However, there might be times when the plugin does not need options, or a callback is desired when a certain event happens. This format of plugin is very similar to the native JQuery event handlers.

// Callback for the Plugin
$("#my-element").alertWhenClickedTwice(function () {
  alert("Be like the native Jquery event handler");
});

Hybrid Format

There are even occasions where a combination of the above two formats might be needed for some degree of customizing over a plain callback.

// Callback with Options
$("#my-element").optionsWithCallback(
  {
    firstOption: "setHigh",
    secondOption: false,
  },
  function () {
    alert("Be like the native Jquery event handler");
  }
);

Below is a modified version of the JQuery Boilerplate.

In order for the callback function to work, the event must be triggered within the plugin itself. Look inside Plugin.prototype.init() for details.

// Boilerplate - Optional Option
(function ($, window, document, undefined) {
  var pluginName = "optionsAreOptional",
    defaults;
  var PluginWrapper = function (element, pluginInfo) {
    var Plugin = function () {
      function checkArgs(index) {
        switch (pluginInfo[index]) {
          case "object":
            // Overwrite defaults if the args item is an object
            Plugin.options = $.extend({}, defaults, pluginInfo.args[index]);
            break;
          case "function":
            // Store the index of where the function location in args
            pluginInfo.functionIndex = index;
            break;
        }
      }
      // Check what type of arguments are supplied to
      // the first and second parameters
      switch (pluginInfo.argsLen) {
        case 1:
          checkArgs(0);
          break;
        case 2:
          checkArgs(0);
          checkArgs(1);
          // Should not have the same parameter types
          if (pluginInfo[0] === pluginInfo[1]) {
            throw [
              "Can not have the first two parameters of the same type of ",
              '"',
              pluginInfo[0],
              '"',
            ].join("");
          }
          break;
      }
    };
    Plugin.prototype = {
      init: function (pluginInfo) {
        // Do Stuff
        this.stuff();
        var $el = $(element);
        // Attaching event listener
        $el.on("optionsAreOptional", function (evt) {
          // Make sure a function exists before executing one
          if (typeof pluginInfo.functionIndex !== "undefined") {
            // Preserve the event and context
            pluginInfo.args[pluginInfo.functionIndex].call(this, evt);
          }
        });
        // Testing out the event listener
        // Use this upon a certain condition being met
        $el.trigger("optionsAreOptional");
        // Do more stuff here
        this.doMoreStuff();
      },
      stuff: function () {
        // Stuff to be done
      },
      doMoreStuff: function () {
        // Even more stuff to be done
      },
      // Add more functions here
    };
    // Initialize plugin
    Plugin();
    Plugin.prototype.init(pluginInfo);
  };
  $.fn[pluginName] = function () {
    var args = Array.prototype.slice.call(arguments),
      argsLen = args.length,
      pluginInfo = {};
    pluginInfo.argsLen = argsLen;
    pluginInfo.args = args;

    function checkArgs(theItem, index) {
      try {
        // Determine if item is a plain object
        if ($.isPlainObject(theItem)) {
          pluginInfo[index] = "object";
        }
      } catch (error) {
        throw "Not a proper object";
      }
      try {
        if ($.isFunction(theItem)) {
          // Determine if item is a function
          pluginInfo[index] = "function";
        }
      } catch (error) {
        throw "Not a proper function.";
      }
    }
    return this.each(function () {
      if (!$.data(this, "plugin_" + pluginName)) {
        // Check for the number of arguments for plugin
        for (var i = 0; i < pluginInfo.argsLen; i++) {
          checkArgs(pluginInfo.args[i], i);
        }
        $.data(
          this,
          "plugin_" + pluginName,
          new PluginWrapper(this, pluginInfo)
        );
      }
    });
  };
})(jQuery, window, document);
<!-- Accompanying Html -->

<!DOCTYPE html>
<html>
  <head>
    <title>Optional Options</title>
    <meta charset="UTF-8" />
    <script src="jquery-1.10.2.min.js"></script>
    <script src="JqueryBoilerPlateOptionalOptions.js"></script>
  </head>
  <body>
    <script>
      $(document).ready(function () {
        // 1) Options Only
        // Only options provided to the plugin
        // This is what most JQuery plugin out there uses
        $("#only-options").optionsAreOptional({
          stuff: "myThings",
        });

        // 2) Function Only
        // This format is similar to the native JQuery event handler
        // Use this if your plugin needs not to have any configuration options
        // In order for this to work, trigger the name of the plugin
        // ex. $('#only-function').trigger("optionsAreOptional")
        // inside your plugin to activate the event handler
        $("#only-function").optionsAreOptional(function () {
          console.log("Only a function");
        });

        // 3) Options and Function
        // Both option and function are provided for this one
        // Use this if a little configuration is needed over the
        // second option
        $("#options-function").optionsAreOptional(
          {
            moreStuff: "moreOfMyThings",
          },
          function () {
            console.log("My callback.");
          }
        );
      });
    </script>
    <h1>The following headers have attached event listeners:</h1>
    <h2 id="only-options">Only options provided for this header.</h2>
    <h2 id="only-function">A function attached to this header.</h2>
    <h2 id="options-function">This header has options and a function.</h2>
  </body>
</html>

Online Demo | Offline Demo