Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple instances of jQuery plugin on same page?

I've seen a lot of different jQuery plugin boilerplates, and read many different jQuery plugin authoring articles, including the official one. However, I seem to still be missing something, fundamentally!

I'm using a mix of code I've seen elsewhere and jQuery's official authoring guidelines.

As you can see from the code, I'm doing everything inside of return this.each(function() { });. This includes my private functions. I assumed that this meant that for each .pluginName(); called, the code would be run and tied to that instance. For example, I'm adding a randID to the end of each of the element IDs, so that if multiple instances are created, the instance can refer to the correct element.

My problem is that when I have two instances on the same page, the second instance's functions (like displayAvailableItems()) are using the first instances randIDs.

I'm assuming 2 things wrong right off the bat: the functions are in the wrong place, and the randID is a bad method of identifying the elements. If I move displayAvailableItems() to just above the retun this.each(function() { });, then availableItem variable is no longer available to it.

Here is the abbreviated version of my code: (pastebin) http://tny.cz/6d3d52a8

$.pluginName = {
     id: 'PluginName'
    ,version: '1.0'
,defaults: { // default settings
    foo: 'bar'
}
};

(function($) {
    //Attach this new method to jQuery
    $.fn.extend({ 

            pluginName: function(params) {
            //Merge default and user parameters
                    var params =  $.extend($.pluginName.defaults, params)
            ,otherGeneralVars = 'example'
        ;

        return this.each(function() {       
            var $t = $(this);

            //Generate a random ID to attach to the elements, so we can have endless (up to 50k) quantities of the plugin on the page
                            var randID = 1 + Math.floor(Math.random() * 50000);
                            //Make sure the randID hasn't been previously used
                            while ($.inArray(randID, usedRandIDs) > -1)
                            {
                                    randID = 1 + Math.floor(Math.random() * 50000);
                            }
                            usedRandIDs.push(randID);
                            randID = '_PluginName' + randID;

            /*
                                    RUN INITIALIZATION SETTINGS
                            */
                            var availableItemsContainerID = 'availableItemsContainer' + randID
                ,tagSearchContainerID = 'tagSearchContainer' + randID
                ,tagSearchID = 'tagSearch' + randID
                ,availableItemsID = 'availableItems' + randID
                ,selectedItemsContainerID = 'selectedItemsContainer' + randID
                ,selectedItemsID = 'selectedItems' + randID
                ,selectedValuesID = 'selectedValuesInputName' + randID
            ;

            //Build element structure
                            $t.append('<div id="' + availableItemsContainerID + '">' +
                                                            '<div id="' + tagSearchContainerID + '">' +
                                                                    '<input id="' + tagSearchID + '" value="' + params.searchDefaultText + '" />' +
                                                            '</div>' +
                                                            '<div id="' + availableItemsID + '"></div>' +
                                                    '</div>' +
                                                    '<div id="' + selectedItemsContainerID + '">' +
                                                            '<div id="' + selectedValuesID + '"></div>' + 
                                                            '<div id="' + selectedItemsID + '"></div>' +
                                                    '</div>');      

            //Show the list of available items
                            displayAvailableItems();

            $('#' + availableItemsContainerID).css({
                              'width': params.availableItemsContainerWidth + params.unitOfMeasurement,
                              'height': params.availableItemsContainerHeight + params.unitOfMeasurement
                            });
                            $('#' + selectedItemsContainerID + ', #' + selectedItemsID).css({
                              'width': params.selectedItemsContainerWidth + params.unitOfMeasurement,
                              'height': params.selectedItemsContainerHeight + params.unitOfMeasurement
                            });

            function displayAvailableItems() {
                                    //Clear out the available items
                                    $("#" + availableItemsID).html('');

                                    //Do other stuff
                            }
        });
               }
       })
        })(jQuery);
like image 342
Luke Shaheen Avatar asked Dec 09 '22 17:12

Luke Shaheen


1 Answers

First, you need to move var params into your this.each, however you will then have a variable hoisting (not absolutely sure if that's actually what is happening, but that's what it appears to be) problem due to using the argument name as a variable name causing params to be undefined. To solve that, just rename params inside of this.each to something else. Example:

$.fn.extend({

    pluginName: function (params) {
        //Merge default and user parameters
        var otherGeneralVars = 'example';

        return this.each(function () {
            var $t = $(this), opts = $.extend({},$.pluginName.defaults, params);

            $t.text(opts.foo + uniqueId);
        });
    }
})

http://jsfiddle.net/M99EY/1/

like image 117
Kevin B Avatar answered Jan 14 '23 15:01

Kevin B