James Howell James Howell - 5 months ago 15
jQuery Question

JQuery plugin not working when used multiple times in a page

I am trying to write a JQuery plugin called grid2carousel which takes some content in a Bootstrap-style grid on desktop devices and becomes a carousel on smaller screens.

The plugin works fine if it is the only instance of it on a page but runs into some problems if there are more than one. I have created a Codepen here to demonstrate the issue:

http://codepen.io/decodedcreative/pen/BzdBpb

Try commenting out one of the components in the HTML section of the codepen, resizing the browser til it becomes a carousel, and then repeating this process again with it uncommented

The plugin works by running an internal function called SetupPlugin every time the browser width is below a breakpoint specified in a data attribute in the HTML. If the browser width exceeds this breakpoint a function called DestroyPlugin reverts the HTML back to its original state. Like so:

checkDeviceState = function(){
if($(window).width()>breakpointValue){
destroyPlugin();
}else{
if(!$element.hasClass('loaded')){
setupPlugin();
}
}
},


Below is my plugin code in its entirety. Could someone give me a pointer as to what I'm doing wrong here?

(function (window, $){
$.grid2Carousel = function (node, options){
var
options = $.extend({slidesSelector: '.g2c-slides', buttonsSelector: '.g2c-controls .arrow'}, {},options),
$element = $(node),
elementHeight = 0,
$slides = $element.find(options.slidesSelector).children(),
$buttons = $element.find(options.buttonsSelector),
noOfItems = $element.children().length + 1,
breakpoint = $element.data("bp"),
breakpointValue = 0;

switch(breakpoint){
case "sm":
breakpointValue = 767;
break;
case "md":
breakpointValue = 991;
break;
case "lg":
breakpointValue = 1199;
break;
}

setupPlugin = function(){

// Add loaded CSS class to parent element which adds styles to turn grid layout into carousel layout
$element.addClass("loaded");

// Get the height of the tallest child element
elementHeight = getTallestInCollection($slides)

// As the carousel slides are stacked on top of each other with absolute positioning, the carousel doesn't have a height. Set its height using JS to the height of the tallest item;
$element.height(elementHeight);

// Add active class to the first slide
$slides.first().addClass('active');


$buttons.on("click", changeSlide);

},

destroyPlugin = function(){
$element.removeClass("loaded");
$element.height("auto");
$buttons.off("click");
$slides.removeClass("active");
},

checkDeviceState = function(){
if($(window).width()>breakpointValue){
destroyPlugin();
}else{
if(!$element.hasClass('loaded')){
setupPlugin();
}
}
},

changeSlide = function(){
var $activeSlide = $slides.filter(".active"),
$nextActive = null,
prevSlideNo = $activeSlide.prev().index() + 1,
nextSlideNo = $activeSlide.next().index() + 1;

if($(this).hasClass('left')){


if(prevSlideNo !== 0){
$nextActive = $activeSlide.prev();
$nextActive.addClass('active');
$slides.filter(".active").not($nextActive).removeClass("active");
}else{
$nextActive = $slides.last();
$nextActive.addClass('active');
$slides.filter(".active").not($nextActive).removeClass("active");
}

}else if($(this).hasClass('right')){


if(nextSlideNo !== 0){
$nextActive = $activeSlide.next();
$nextActive.addClass('active');
$slides.filter(".active").not($nextActive).removeClass("active");
}else{
$nextActive = $slides.first();
$nextActive.addClass('active');
$slides.filter(".active").not($nextActive).removeClass("active");
}

}
},

getTallestInCollection = function(collection){

$(collection).each(function(){
if($(this).outerHeight() > elementHeight){
elementHeight = $(this).outerHeight();
}
});

return elementHeight;

};

setupPlugin();
checkDeviceState();
$(window).on("resize", checkDeviceState);

}




$.fn.grid2Carousel = function (options) {
this.each( function (index, node) {
$.grid2Carousel(node, options)
});

return this
}
})(window, jQuery);


Many thanks,

James

Answer

Please check line #30 in your plugin code,it looks that you've just forget to add var keyword so instead of creating local variables to store functions setupPlugin, destoryPlugin and so on you've created global variables and then each new initialization of your plugin is rewriting this functions to point to a newly created slider.

setupPlugin = function(){

should be

var setupPlugin = function(){

Updated code here.