For exercise purposes I am creating a jQuery Plugin, a simple Image Slider. I use a Pattern from Boilerplate - jQuery Plugins.
During the initializing process everything works as expected, every Instance gets the right values (widths and heights, also event binding) needed for setup.
The trouble starts when I try to pass a calculated slides-width to a function doing the animation (clicked on next button). Every value which I tried to save was overwritten by the last instance - ok, that's what prototype inheritance does, as I learned.
I googled a lot and found (not only) this solution on stockoverflow: global or local variables in a jquery-plugin. The accepted answer suggests to store values which need to be private in the HTML Markup, the data-whatever attribute.
This works very good, but is not very nice.
The second answer seemed to be more elegant, keeping real private variables in the scope of every instance:
(function($) {
$.pluginName = function(element, options) {
....
var plugin = this;
....
// a public method
plugin.foo_public_method = function() {
....
}
// private methods
var foo_private_method = function() {
....
}
plugin.init();
} ....
Looked pretty simple - but I am not able to implement this solution!
So my Question is: how do I implement a private variable in the following plugin pattern? (And how do I call it properly from inside Plugin.prototype ... )
I created a Fiddle with my plugin. An abstract of the code:
(function ($, window, document, undefined) {
var pluginName = "easyCarousel";
// default configuration object
defaults = {
... default values here, css etc
}
};
// The actual plugin constructor
function Plugin(element, options) {
this.element = element;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function () {
var options = this.options;
this.options.stage = $(this.element);
.... calling/starting views and controllers
},
buildCollectionView: function (options, Helper) {
.... setting markup, applying css, calulating dimensions
},
buildStageView: function (options, Helper) {
.... setting markup, applying css
.... storing calculated slide width in data Attribute
stage.attr({
'data-slidewidth': width,
'data-stagewidth': setWidth
});
},
buildTheatreView: function (options, Helper) {
.... setting markup, applying css
},
buildNavigationView: function (options) {
.... setting markup
},
navigationController:
function (options, slideForward, slideBackward) {
.... event binding
pubSub.on("navigation:arrownext:click", function (e) {
slideForward(options, e);
});
$('.carousel__arrownext', options.theatre)
.bind('click', function () {
pubSub.trigger("navigation:arrownext:click", this);
});
},
slideForwardAnimation: function (options, e) {
.... reading stored width value from data Attribute
$element.animate({
"left": "-=" + slideWidth
})
},
setDimensionsHelper: function (options) {
.... calculating an returning dimensions of the slider
},
eventBusHelper: function (options) {
// integrating third party eventbus
}
};
$.fn[pluginName] = function (options) {
return this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName,
new Plugin(this, options));
}
});
}})(jQuery, window, document);
I hope my code example is not to complicated/long to view.
As you may see I'm quite new to advanced Javascript patterns - and right now I really stuck. I already spend many many hours in this problem. So every attempt to help is very appreciated. Also of course every review on the code.
Thanks in advance :)
All you need to do is define the variables within your prototype (directly or from within a method in the prototype) rather than doing it in your constructor. Variables defined in the constructor will be shared among all instances of your plugin, while variables defined in the prototype will be per-instance.
Also, you have no "var" keyword in front of your "defaults" definition, so you're actually creating a global variable called "defaults" rather than one that's scoped to just your closure.
This is what I'd recommend:
or even better: