Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Plugin Authoring - Set different options for different elements

I have created a jQuery plugin that works great with the exception of being able to call the plugin on different objects and each object retaining the options it was given. The problem is that if I call the plugin on one object, say:

$('#myDiv1').myPlugin({
    option1: 'some text',
    option2: true,
    option3: 'another option value'
});

then call the plugin again on another object, say:

$('#myDiv2').myPlugin({
    option1: 'different text',
    option2: false,
    option3: 'value for myDiv2'
});

Then if I go back and try to do something with #myDiv1 that needs its original options to still be intact, ie:

$('#myDiv1').myPlugin.update();

it won't have it's original options, but they will be overridden by the options for #myDiv2. What's the proper way to do this so that each object will retain the original options given to it? (And here's some example code of what I'm doing in the plugin)

(function($) {
$.fn.myPlugin = function(options) {

    // build main options before element iteration
    var opts = $.extend({}, $.fn.myPlugin.defaults, options);

    _option1 = opts.option1;
    _option2 = opts.option2;
    _option3 = opts.option3;

    // iterate all matched elements
    return this.each(function() {
        callPluginFunctions( this, opts );
    });

};

    ....code continued....

I realize this is some kind of scope creep or something. So, how do I get my options to stay attached and remain in the scope of the original object (ie #myDiv1) that they were given to.

EDIT: In doing some research I see that you can store data to an object using jQuery's .data function, and the docs say jQuery UI uses it extensively. Would the proper thing to do here be store the options on the object using .data, then when referenced later use the options stored in .data ???

like image 226
Ryan Avatar asked Jan 29 '10 15:01

Ryan


1 Answers

First, you will generally want to handle the command within your extension method. Second, you should be attaching configurations to each item...

(function($){
var defaultOptions = { /* default settings here */ };

//called on the native object directly, wrap with $(obj) if needed.
function initializeObject(obj, options) {
  //assign the options to the object instance.
  $(obj).data('myPlugin-options', $.extend(defaultOptions, options) );
  //do other initialization tasks on the individual item here...
}

function updateObject(obj) {
  // use $(obj).data('myPlugin-options');
}

function setOption(obj, key, value) {
  var d = $(obj).data('myPlugin-options');
  d[key] = value;
  $(obj).data('myPlugin-options', d);
}

$.fn.myPlugin = function(command, option, val) {
  if (typeof command == "object") {
    //initialization
    return this.each(function(){
      initializeObject(this, command);
    });
  }
  if (typeof command == "string") {
    // method or argument query
    switch (command.toLowerCase()) {
      case 'option':
        //get value, return the first item's value
        if (typeof val == undefined) return this.eq(0).data('myPlugin-options')[option];
        //set option value
        return this.each(function() {
          setOption(this, option, val);
        });

      case 'update':
        return this.each(function() {
          updateObject(this);
        });
      //other commands here.
    }
  }
}
})(jQuery)

With the above example, you have a generic template for a jQuery extension, It's usually good form to have the following convention for use..

Initialization:
  $(...).myPlugin({ initialization-options-here });
Command:
   $(...).myPlugin('command-name'); //where command can be update, etc.
Get Option:
  var myValue = $(...).myPlugin('option', 'option-name');
Set Option:
  $(...).myPlugin('option', 'option-name', newValue);

Updated to use .data off of each individual obj.

like image 73
Tracker1 Avatar answered Sep 24 '22 03:09

Tracker1