Question

I am trying to create custom tab widget in Javascript and jquery. I have created the tab object but facing problem while assigning click event take a look towards code. I have attached event but it is working only on last object. Can someone suggest better way to do this

function TabTitleBox(TabName){
  this.SelectedBox = 0;
  this.TitleBoxContainer = $('<div>'+TabName+'</div>');
  this.TitleBoxContainer.addClass("STATSTab");
  this.TitleBoxContainer.addClass("UnSelectedTab");
  this.TitleBoxContainer.on('mouseenter',function(){
    CurrentColor = $(this).css('background-color');
    var t = tinycolor(CurrentColor);
    var NewColor = tinycolor.saturate(t,50);
    $(this).css("background-color",NewColor);
  }).on('mouseleave',function(){
    $(this).removeAttr('style','background-color');
  });

  this.SelectTab = function(){
    if(this.SelectedBox == 0){
    $(this.TitleBoxContainer).removeClass("UnSelectedTab");
    $(this.TitleBoxContainer).addClass("SelectedTab");
    this.SelectedBox = 1;
    }
  }

  this.RemoveStyle = function(){
    $(this.TitleBoxContainer).removeAttr('style','background-color');
  }

  this.UnSelectTab = function(){
    if(this.SelectedBox == 1){
    $(this.TitleBoxContainer).removeClass("SelectedTab");
    $(this.TitleBoxContainer).addClass("UnSelectedTab");
    this.SelectedBox = 0;
    }
  }

  return this;
}


TabContainer = new Array();
TabContainer.push(new TabTitleBox("Is first tab"));
TabContainer.push(new TabTitleBox("Is Second tab"));
TabContainer.push(new TabTitleBox("Is Third tab"));
TabContainer.push(new TabTitleBox("Is Fourth tab"));

for(var x = 0; x < TabContainer.length ; x++){
  Tab = TabContainer[x];
  $('body').append(Tab.TitleBoxContainer);
  $(Tab.TitleBoxContainer).on('click', function(){
    if(Tab.SelectedBox == 1){
      Tab.UnSelectTab();
      Tab.SelectedBox = 0;
    }else{
      Tab.SelectTab();
      Tab.SelectedBox = 1;
    }
    Tab.RemoveStyle();
  });
}

found out the solution thanks for the answer changes done in my code as follows. Link can be found here http://skondgekar.comeze.com/Test.php

        TabContainer = new Array();
        TabContainer.push(new TabTitleBox("Is first tab"));
        TabContainer.push(new TabTitleBox("Is Second tab"));
        TabContainer.push(new TabTitleBox("Is Third tab"));
        TabContainer.push(new TabTitleBox("Is Fourth tab"));

        var funcs = [];

        for(var x = 0; x < TabContainer.length ; x++){
            Tab = TabContainer[x];
            funcs[x] = (function(Tab){
                return function(){
                    $(Tab.TitleBoxContainer).on('click', function(){
                            if(Tab.SelectedBox == 1){
                                Tab.UnSelectTab();
                            }else{
                                Tab.SelectTab();
                            }
                            Tab.RemoveStyle();
                        });
                }
                })(Tab);

            funcs[x]();
            $('body').append(Tab.TitleBoxContainer);
        }
Was it helpful?

Solution

You need to implement a proper closure on your click handler.

Let me point you in the right direction:

// (This is untested, but should be pretty close to what you need)

for(var x = 0; x < TabContainer.length ; x++){
  Tab = TabContainer[x];
  $('body').append(Tab.TitleBoxContainer);
  $(Tab.TitleBoxContainer).on('click', myClosure(Tab)); // Calling the closure
}

function myClosure(Tab) { // Binding the current value of the Tab to the function it
    return function()     // and returning the function
        if(Tab.SelectedBox == 1){
          Tab.UnSelectTab();
          Tab.SelectedBox = 0;
        }else{
          Tab.SelectTab();
          Tab.SelectedBox = 1;
        }
        Tab.RemoveStyle();
    });
}

Another way to write the closure would be:

for(var x = 0; x < TabContainer.length ; x++){
  Tab = TabContainer[x];
  $('body').append(Tab.TitleBoxContainer);
  $(Tab.TitleBoxContainer).on('click', function(theRealTab) { // Creating closure
    return function(){
      if(theRealTab.SelectedBox == 1){
        theRealTab.UnSelectTab();
        theRealTab.SelectedBox = 0;
      }else{
        theRealTab.SelectTab();
        theRealTab.SelectedBox = 1;
      }
      theRealTab.RemoveStyle();
    }
  })(Tab);    // Binding the current value of Tab to the function variable theRealTab
}

Without the closure, the Tab variable in your click functions will always be the current value of the variable (in this example - the last Tab processed if your for loop).

For more info:

Closures inside loops - The accepted answer has an example very similar to this

How do closures work

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top