James Skidmore
James Skidmore

Reputation: 50338

How to have multiple instances of jQuery plugin on single page?

I'm writing a simple jQuery plugin, but I'm having trouble being able to use multiple instances on a page.

For instance, here is a sample plugin to illustrate my point:

(function($) {
  $.fn.samplePlugin = function(options) {
    if (typeof foo != 'undefined')
    {
      alert('Already defined!');
    } else {
      var foo = 'bar';
    }
  };
})(jQuery);

And then if I do this:

$(document).ready(function(){
  $('#myDiv').samplePlugin({}); // does nothing
  $('#myDiv2').samplePlugion({}); // alerts "Already defined!"
});

This is obviously an over-simplified example to get across the point. So my question is, how do I have two separate instances of the plugin? I'd like to be able to use it across multiple instances on the same page.

I'm guessing that part of the problem might be with defining the variables in a global scope. How can I define them unique to that instance of the plugin then?

Thank you for your guidance!

Upvotes: 18

Views: 34576

Answers (9)

Scott M
Scott M

Reputation: 119

Just throwing my solution in here:

(function ($){

    $.fn.plugin = function (options){
        var settings = $.extend({}, $.fn.plugin.defaults, options);
        settings.that = $(this);
        $.fn.plugin.init (settings);
    };

    $.fn.plugin.defaults = { objval: 'default' };

    $.fn.plugin.init = function (settings){
        settings.that.val (settings.objval);
    };

}( jQuery ));

$('#target1').plugin ({objval: 'not default'});
$('#target2').plugin ();

DEMO

The settings variable is isolated every time you initialize the object.

Upvotes: 2

Roman Yudin
Roman Yudin

Reputation: 973

html:

<code class="resize1">resize1</code>
<code class="resize2">resize2</code>


<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script type="text/javascript">
       jQuery(document).ready(function($) {
           $('.resize1').ratiofix({message:'resize1'});
           $('.resize2').ratiofix({message:'resize2'});
       });
</script>

I have found 2 solutions - the first one is jquery widget factory http://jqueryui.com/widget/ js code:

$.widget("custom.ratiofix",{
    options:{
        message:"nothing"
    },
    _create:function (){
        var self=this;
        this.setListeners();
    },
    setListeners:function (){
        var self=this;
        $(window).on('resize',$.proxy(self.printMsg,self));
    },
    printMsg:function (){
         console.log(this.options.message);
    }
});

And the second (without widget factory):

(function ($){
var Ratiofix = {
  init: function(options, elem) {
    this.options = $.extend({},this.options,options);
    this.elem  = elem;
    this.$elem = $(elem);
    this.setListeners();
    return this;
  },
  options: {
    message: "No message"
  },
  printMsg: function(){
     console.log(this.options.message);
  },
  setListeners:function (){
    var self=this;
    this.$elem.on('click',function (){
         console.log(self.options.message);
    });
    $(window).on('resize',$.proxy(self.printMsg, self));
  }
};

  $.fn.ratiofix=function (options){
    this.init= function(options, elem) {
      this.options = $.extend({},this.options,options);
      this.elem  = elem;
      this.$elem = $(elem);

      return this;
  };

    if ( this.length ) {
      return this.each(function(){
        var ratiofix = Object.create(Ratiofix);
        ratiofix.init(options, this); 
        $.data(this, 'ratiofix', ratiofix);
      });
    }


  };
})(jQuery);

In both cases plugins work separately and have own settings. In my case - 2 widgets listen to window resize and print to console own options.message

Upvotes: 3

steph
steph

Reputation: 1

This worked a treat for me! I had specific parameters for which pages/places I wanted to run a plugin and was able to achieve success by using a simple if statement. Hope this helps someone!

<!-- Begin JQuery Plugin Foo -->
<script src="js/foo_fun.js"></script>

<?php 
if(substr_count(strtolower($currentUrl),"member")>0)
{
?>
    <script>
    $(document).ready(function(){
        $('#vscroller').vscroller({newsfeed:'news_employee.xml', speed:1000,stay:2000,cache:false});
    });
    </script>
<?php
}
else
{
?>
    <script>
    $(document).ready(function(){
        $('#vscroller').vscroller({newsfeed:'news_company.xml', speed:1000,stay:2000,cache:false});
    });
    </script>
<?php
}
?>
<!-- End JQuery Foo--> 

Upvotes: -1

Cyrano_fr
Cyrano_fr

Reputation: 1

I had the same problem : how to use many instances of a plugin on only one form ? The usual way fails because in fact, the instance is not an instance of the plugin : it is an instance of jQuery. So, if more than one element is defined to be managed by a plugin, each definition overrides the previous parameters.

It was necessary to have a look on the problem from another side.

A plugin is usually made to react on a specific event for a specific element. e.g.. onclick on a button, or when the mouse is over the element. In my case, I had to use an autocomplete plugin for a city field, but my form has 5 tabs and in total 4 fields for the cities for 4 different parts of the information to be collected. For each fields, parameters are specifics.

By the way, I've realised iI don't need to have the plugin active everytime : just on the appropriate event on the field is enough.

So I had an idea : an event manager for each element. When the event appends, so I define the plugin action. Some code will be more efficient to explain : imagine you have 3 div blocks and your plugin must change the colours, but with specifics colours depending on which div is affected.


$(document).ready(function(){
    // Wich elements are affected by the plugin
    var ids = ['myDiv1','myDiv2','myDiv3'];
    // foe each one :
    for (v in ids) 
    {
        //define from an event :
        $('#'+ ids[v]).focus(function()
        {
            // depending which id is active :
            var  aParams, idDiv = $(this).attr('id');
            // Choosing the right params
            switch(idDiv)
            {
                case 'myDiv1':
                    aParams = {'color': '#660000', 'background-color': '#0000ff'};
                    break;
                case 'myDiv2':
                    aParams = {'color': '#006600', 'background-color': '#ff00ff'};
                    break;
                case 'myDiv3':
                    aParams = {'color': '#000066', 'background-color': '#ff0000'};
                    break;
                default:
                    aParams = {'color': '#000000', 'background-color': '#ffffff'};
            };
            // Defining the plugin on the right element with the right params
            $(this).myPlugin(
            {
                colors: aParams
            });
        });
    }
});

And this works fine.

Sorry if my English is not perfect - I hope you understand well.

Upvotes: -4

WhyNotHugo
WhyNotHugo

Reputation: 9924

You need to use this.foo instead of var foo, so that the variable is only related to the current object.

Upvotes: 1

manny
manny

Reputation: 1948

instead of writing this

$("#divid1").samplePlugin();
$("#divid2").samplePlugin();

you can do this way

$.plugin('samplePlugin1', samplePlugin);
$("#divid1").samplePlugin1();

$.plugin('samplePlugin2', samplePlugin);
$("#divid2").samplePlugin2();

You can have much details from here http://alexsexton.com/?p=51

Upvotes: 1

Logan
Logan

Reputation: 179

I have the very same problem but i find a very handy solution i´ll post it for someone who may have this problem

when you define your variables insinde the plugin you could use the .data() to store all the variables you define

like this

(function($) {
  $.fn.samplePlugin = function(options) {
    var base = this;
    this.foo // define foo

    // do stuff with foo and other variables

    // Add a reverse reference to the DOM object
    this.data("pluginname", base);

  };})(jQuery);

And when you want to use the same foo variable you should retrive the reference with this:

base = this.data("pluginname");
base.foo

Hope it helps

Logan

Upvotes: 17

Nathan Long
Nathan Long

Reputation: 126122

I'm not sure what you mean by having more than one instance of a plugin. A plugin would be available to use on any element.

This comment doesn't clarify much for me:

So say that it was a plugin that took a "color" parameter and turned the object into that color. Well, in that case you'd need multiple instances, as you're dealing with more than one page element turning more than one color.

In this case, you would pass in different colors are arguments as needed:

$('div#foo').makeColor('red');
$('div#bar').makeColor('blue');

Each time you call the plugin, it will use whatever arguments you give it. The plugin isn't a class that needs instances.

Upvotes: 2

Scott Evernden
Scott Evernden

Reputation: 39986

To answer your question directly, you can use jQuery.noconflict() to avoid namespace collisions and thus potentially have multiple instantiations on a page..

var $j = jQuery.noConflict();
// Use jQuery via $j(...)
$j(document).ready(function() {
  // etc

check here

But I question your design. Why are you writing a plugin that appears to not operate on a jQuery wrapped set ? .. Plugins should be written to assume they are operating on a jQuery array held in 'this'. In which case any state can be stored in each of the items being acted upon... But maybe you are building something different?

Please review this page

Upvotes: 1

Related Questions