0

I have the following small plugin which shifts class of 'focus' between a set of elements. This issue is, If I have multiple sets on a single page, with a new instance of the plugin applied to each set, there appears to be a conflict between the setTimeout function not staying within the plugin instance context.

(function($){

   $.fn.focusChanger = function(){

      return this.each(function(){

        //VARIABLES     
        var $this = $(this),
            $targets = $this.find('.focus-target'),
            numTargets = $targets.length,
            autoSpeed = 2500,
            autoChangeT = setTimeout(_autoChange, 500),
            currentIndex = numTargets;

        /////////////// Handlers ///////////////
        $this.hover(
            function () {
                //stop auto-changing
                _autoReset();
            },
            function () {
                autoChangeT = setTimeout(_autoChange, 500);
            }
        );


        /////////////// Functions ///////////////

        //Change Slide
        _changeFocus = function(newIndex){
            $targets.eq(currentIndex).removeClass("focus");
            $targets.eq(newIndex).addClass("focus");
            currentIndex = newIndex;
        };

        //auto slide changer
        function _autoChange() {
            console.log($this);
            var newIndex;
            if(currentIndex >= numTargets - 1){
               newIndex = 0;
            }else{
               newIndex = currentIndex + 1;
            };
            _changeFocus(newIndex);
            autoChangeT = setTimeout(_autoChange, autoSpeed);
        };
        // stop auto slide changer
        function _autoReset() {
            clearTimeout(autoChangeT);
            $targets.eq(currentIndex).removeClass("focus");
        };

      });//end each (plugin)

   };// end fn

})(jQuery);

$(document).ready(function(){
    if($.fn.focusChanger){
        $('.focus-change-set').focusChanger();
    }
});

http://jsfiddle.net/Swpw2/8/

The above fiddle shows a working version of the plugin when applied to a single instance. Uncomment the second HTML block inside to see it break.

I have done my best to understand the following issue, but haven't been able to apply it to my plugin setup, as I am not passing this into the setTimout.

How can I keep the instances of the plugin (and I suspect setTimeout specifically) from interfering with each other?

Community
  • 1
  • 1
tjames
  • 23
  • 4
  • You can actually store a timeout in jQuery's data() on each element seperately. – adeneo May 15 '13 at 23:35
  • Are you able to show how that would work? or link to an applicable resource (http://api.jquery.com/data/ isn't much help)? Thanks! – tjames May 15 '13 at 23:58

1 Answers1

1

Change:

_changeFocus = function(newIndex){

to:

function _changeFocus (newIndex){

or:

var _changeFocus = function(newIndex){

Without the var or function keyword, you're declaring a global variable, so both instances are calling the same closure.

FIDDLE

I figured this out by adding IDs to all the DIVs, setting breakpoints in the Javascript debugger. When I was in _autoChange, $this and $targets pointed to the first DIV. When I stepped into _changeFocus, they suddenly changed to point to the second DIV. That's when I noticed that you used different syntax to define these functions.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Doh. Amateur mistake, over-complexifying an issue down the wrong path! Thanks buddy. – tjames May 16 '13 at 00:08
  • If I had a dime for every question where the actual cause was totally different from what the OP was looking at.... – Barmar May 16 '13 at 00:13