5
\$\begingroup\$

I have this script that I need to run a tab (jquery). Mainly I need to hide some div and add class (you sure have understood).

How should it be written in a more elegant and readable?

function fun1(){
$('#tab1 a').addClass('selected');
$('#tab2 a').removeClass('selected');
$('#tab3 a').removeClass('selected');

document.getElementById('div1').style.display='block';
document.getElementById('div2').style.display='none';
document.getElementById('div3').style.display='none';
}
function fun2(){
$('#tab1 a').removeClass('selected');
$('#tab2 a').addClass('selected');
$('#tab3 a').removeClass('selected');

document.getElementById('div1').style.display='none';
document.getElementById('div2').style.display='block';
document.getElementById('div3').style.display='none';
}
function fun3(){
$('#tab1 a').removeClass('selected');
$('#tab2 a').removeClass('selected');
$('#tab3 a').addClass('selected');

document.getElementById('div1').style.display='none';
document.getElementById('div2').style.display='none';
document.getElementById('div3').style.display='block';
}

window.onload = function() {
    document.getElementById('tab1').onclick=fun1;
    document.getElementById('tab2').onclick=fun2;
    document.getElementById('tab3').onclick=fun3;

    document.getElementById('div1').style.display='block';
    document.getElementById('div2').style.display='none';
    document.getElementById('div3').style.display='none';
}
\$\endgroup\$

3 Answers 3

3
\$\begingroup\$

It sure could be written in a more agreeable way ;)

First off, you might want to handle more tabs and divs in the future, so you can gather their ids into an array:

Either 2 arrays :
var tabs = ['tab1','tab2','tab3'];
var divs = ['div1','div2','div3'];

Or maybe 1 array with objects like { tabId : 'tab1' , divID : 'div1' }
Or maybe you could even just consider tracking how many tabs you have:
var tabCount = 3;

And go from there.

Also, using .onclick is too old skool, consider using https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener

Personally, I would probably go for something like this ( after renaming the divs and tabs tab0 ,tab1,tab3 and div0,div1, and div2 ):

var tabCount = 3;

function handleTabClick()
{
  //`this` contains the selected tab
  var selectedTabId = this.id;
  //Compare, and contrast
  for( var i = 0 ; i < tabCount ; i++ )
  {
    //Make sure the clicked tab id looks selected 
    if( 'tab' + i == selectedTabId )
    {
      $('#' + selectedTabId + ' a').addClass('selected');
      document.getElementById('div'+i).style.display='block';
    }
    else
    {
      $('#' + tab + i + ' a').removeClass('selected');  
      document.getElementById('div'+i).style.display='none';
    }
  }
}

document.addEventListener( "load" , function() initializeTabs{

  for( var i = 0 ; i < tabCount ; i++ )
  {
    //Get element
    var element = document.getElementById('tab'+i);
    //Add generic even listener
    element.addEventListener( "click" , handleTabClick );
    //Only show the first block ( when i is 0, and hence equates false )
    if( i )
      element.style.display='none';
    else
      element.style.display='block';   
  }
});

I did not test this code, but the intent and approach should be clear.

\$\endgroup\$
2
\$\begingroup\$

You're hardly using jQuery at all here. You can either get rid of jQuery entirely (as in konijn's answer), or you can use it to your advantage. Either way is perfectly acceptable.

Secondly, the logic is basically the same for each tab, it's only the elements that change. What you have now is very repetitive because you basically re-do the logic for each tab. There's no need for this.

And as konijn points out, you're using old school event handling; again you can go with konijn's jQuery-less code, or you can use jQuery to your advantage.

Lastly, instead of having to hard-code your element IDs, it's more flexible to declare the relationship between a tab link and a DIV in HTML. For instance:

<a class="tab" href="#div1">1st tab</a>
<a class="tab" href="#div2">2nd tab</a>
<a class="tab" href="#div3">3rd tab</a>

<div id="div1">...</div>
<div id="div2">...</div>
<div id="div3">...</div>

Note that the href attribute for the links point to a DIV. The nice part is that this works even if the user doesn't have JavaScript enabled; a #someId link will scroll the page to show the element with that ID. It's not the same as having real tabs, but it's as good a substitute as any.

Point is that if you add more tabs, you only have to change the HTML. The JavaScript will "just work".

In the code below, I'm using jQuery to put all this together. Here's a demo

function initializeTabs(selector) {
  var tabs = $(selector), // get the tab links
      first;

  // helper function to hide a tab's element
  function deselectTab(tab) {
    tab.removeClass("selected").data("pane").hide();
  }

  // helper function to show a tab's element
  function selectTab(tab) {
    tab.addClass("selected").data("pane").show();
  }

  // get the elements that the tabs should show/hide
  tabs.each(function () {
    var tab = $(this),
        paneId = tab.attr("href");
    tab.data("pane", $(paneId));
  });

  // set up the click-event handling
  tabs.on("click", function (event) {
    var target  = $(this);

    // don't follow the links
    event.preventDefault()

    // stop here if the tab's already selected
    if( target.hasClass("selected") ) { return; }

    // hide the currently selected tab
    deselectTab(tabs.filter(".selected"));

    // show the clicked tab
    selectTab(target);
  });

  // show the first tab
  first = tabs.eq(0);
  selectTab(first);

  // hide the others
  tabs.not(first).each(function () {
    deselectTab($(this));
  });
}

// onload
$(function () {
  initializeTabs("a.tab");
});
\$\endgroup\$
0
\$\begingroup\$

Thought id add a version in here that simplifies the JavaScript but relies on the html using specific classes.

HTML

<div class="tabs-nav">
    <a href="#" class="item1 selected">Item 1</a>
    <a href="#" class="item2">Item 2</a>
    <a href="#" class="item3">Item 3</a>
</div>

<div class="content content-item1"></div>
<div class="content content-item2 hidden"></div>
<div class="content content-item3 hidden"></div>

JAVASCRIPT

$(function () {
    $('.tabs-nav a').click(function (e) {
        e.preventDefault();
        if (!$(this).hasClass("selected")) {
            $('.tabs-nav a').removeClass("selected");
            $('.content').hide();

            $('.content-' + $(this).attr("class")).show();
            $(this).addClass("selected");
        }
    });
});

CSS

.hidden{display:none;}
.selected{font-weight:bold;}

Job done! I am using classes but you could modify the code to use ids if you prefer. throwing it into the mix as an alternative to the 2 suggestions you already have.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.