I am writing a JQuery plugin for a project I'm working on which turns from tabbed content on desktop devices to an accordion on mobile devices. I've used JQuery Boilerplate (https://github.com/jquery-boilerplate/jquery-boilerplate/blob/master/dist/jquery.boilerplate.js) as an initial pattern for my plugin.
The plugin is called on any element with the class ".tabs2accordion" as shown here:
$(".tabs2accordion").tabs2Accordion({state:"desktop"});
The plugin works as expected if there is only one element with ".tabs2accordion" class on a page but starts to malfunction as soon as another element with the same class is added to the page. I've created a codepen of the basic code to demo the issue. To show the issue, on a window size of >768px try clicking any of the titles and observe how the content below changes as each title is clicked. Next uncomment the block of HTML and try clicking on the titles again.
http://codepen.io/decodedcreative/pen/MyjpRj
I have tried looping through each element with the class "tabs2accordion" like this:
$(".tabs2accordion").each(function(){
$(this).tabs2Accordion({state:"desktop"});
});
But this didn't fix the issue either.
Any ideas?
I have not used jQuery Boilerplate, but I believe the problem here is with your variable called plugin
.
Nowhere in your code do you declare a variable called plugin
. When I stop the debugger in Plugin.prototype.showTabContent
, I can evaluate window.plugin
and it returns the global value for plugin.
In the constructor for Plugin, the first line reads plugin= this;
. Since plugin
is not defined, it is declaring the variable at global scope on the window
object.
The fix is to pass a reference to the plugin
object when setting up the $().on()
hook. The data passed is available in the event handlers via the event
parameter that is passed in the data
property.
Here is the solution (at http://codepen.io/shhQuiet/pen/JXEjMV)
(function($, window, document, undefined) {
var pluginName = "tabs2Accordion",
defaults = {
menuSelector: ".tabs2accordion-menu",
tabContentSelector: ".tabs2accordion-content"
};
function Plugin(element, options) {
this.element = element;
this.$element = $(this.element);
this.options = $.extend({}, defaults, options);
this.$menu = $(this.element).find(this.options.menuSelector),
this.$tabs = $(this.element).find(this.options.tabContentSelector),
this.$accordionTriggers = $(this.element).find(this.$tabs).find("h3");
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
//Set all the tab states to inactive
this.$tabs.attr("data-active", false);
//Set the first tab to active
this.$tabs.first().attr("data-active", true);
//If you click on a tab, show the corresponding content
this.$menu.on("click", "li", this, this.showTabContent);
//Set the dimensions (height) of the plugin
this.resizeTabs2Accordion({
data: this
});
//If the browser resizes, adjust the dimensions (height) of the plugin
$(window).on("resize", this, this.resizeTabs2Accordion);
//Add a loaded class to the plugin which will fade in the plugin's content
this.$element.addClass("loaded");
console.log(this.$element);
},
resizeTabs2Accordion: function(event) {
var contentHeight;
var plugin = event.data;
if (!plugin.$element.is("[data-nested-menu]")) {
contentHeight = plugin.$tabs.filter("[data-active='true']").outerHeight() + plugin.$menu.outerHeight();
} else {
contentHeight = plugin.$tabs.filter("[data-active='true']").outerHeight();
}
plugin.$element.outerHeight(contentHeight);
},
showTabContent: function(event) {
var $target;
var plugin = event.data;
plugin.$menu.children().find("a").filter("[data-active='true']").attr("data-active", false);
plugin.$tabs.filter("[data-active='true']").attr("data-active", false);
$target = $($(this).children("a").attr("href"));
$(this).children("a").attr("data-active", true);
$target.attr("data-active", true);
plugin.resizeTabs2Accordion({data: plugin});
return false;
},
showAccordionContent: function(event) {
var plugin = event.data;
$("[data-active-mobile]").not($(this).parent()).attr("data-active-mobile", false);
if ($(this).parent().attr("data-active-mobile") === "false") {
$(this).parent().attr("data-active-mobile", true);
} else {
$(this).parent().attr("data-active-mobile", false);
}
}
};
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin(this, options));
}
});
};
})(jQuery, window, document);
$(window).on("load", function() {
$(".tabs2accordion").tabs2Accordion({
state: "desktop"
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With