0

I organized my tabs this way:

<ul id="tabs">
    <li class="selected"><a href="#div1">DIV1</a></li>
    <li class><a href="#div2">DIV2</a></li>
    <li class><a href="#div3">DIV3</a></li>
</ul>
<div id="tabs_content">
    <div id="div1" style="display: block;"><textarea name="div1" rows="7" cols="108"></textarea></div>
    <div id="div2" style="display: none;"><textarea name="div2" rows="7" cols="108"></textarea></div>
    <div id="div3" style="display: none;"><textarea name="div3" rows="7" cols="108"></textarea></div>
</div>

I would like that when I press one of the link inside the <li> element, the corrispondend Div become visible with display: block and the others are changed to display: none
Also I would like to do the same with the "selected" class on the clicked <li> element.

Is this possible?

I tried with:

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

It works if I pass the ID by reference with onclick="" but I would like to avoid this.

Solution:

function selectTab(source, parent)
{
    document.getElementById('div1').style.display = 'none';
    document.getElementById('div2').style.display = 'none';
    document.getElementById('div3').style.display = 'none';
    document.getElementById(source).style.display = 'block';

    var elements = [].slice.apply(document.getElementsByClassName('selected'));
    for (var i = 0; i < elements.length; i++) {
        elements[i].className = '';
    }

    parent.className = 'selected';
}
2
  • 1
    Resetting all elements before you set them correctly may cause flickering. Also, getting the elements by ID every click is rather unnecessary. Also, you can pass on this as argument, on which you can get the id of that element by that.id or that.href for the id in the href tag. Take a look at my question for a more elegant answer if you ain't using jQuery. Commented Sep 29, 2013 at 16:23
  • Thanks for the input! I'll study your solution. Commented Sep 29, 2013 at 16:24

3 Answers 3

1

Possibly this is what you want, cross-browser (IE5.5+)

CSS

.selected {
    background-color: green;
}
.hide {
    display: none;
}

HTML

<ul id="tabs">
    <li class="selected"><a href="#div1">DIV1</a>

    </li>
    <li class><a href="#div2">DIV2</a>

    </li>
    <li class><a href="#div3">DIV3</a>

    </li>
</ul>
<div id="tabs_content">
    <div id="div1">
        <textarea name="div1" rows="7" cols="108"></textarea>
    </div>
    <div id="div2" class="hide">
        <textarea name="div2" rows="7" cols="108"></textarea>
    </div>
    <div id="div3" class="hide">
        <textarea name="div3" rows="7" cols="108"></textarea>
    </div>
</div>

javascript

var tabs = document.getElementById("tabs"),
    tabs_content = document.getElementById("tabs_content"),
    divs = tabs_content.getElementsByTagName("div"),
    divsLength = divs.length,
    lis = tabs.getElementsByTagName("li"),
    lisLength = lis.length;

tabs.onclick = function (evt) {
    var e = evt || window.event,
        target = e.target || e.srcElement,
        href,
        id,
        index,
        div;

    if (target.tagName.toUpperCase() === "A") {
        for (index = 0; index < lisLength; index += 1) {
            lis[index].className = "";
        }

        target.parentNode.className = "selected";
        href = target.attributes.href.nodeValue;
        if (href && href.charAt(0) === "#") {
            id = href.slice(1);
            for (index = 0; index < divsLength; index += 1) {
                div = divs[index];
                if (id === div.id) {
                    div.className = "";
                } else {
                    div.className = "hide";
                }
            }
        }
    }
};

jsfiddle

Sign up to request clarification or add additional context in comments.

2 Comments

Where do I have to place the onload function in the html?
There is no onload function in either the question or answers. I assume that you are asking another question, for which you should create a new question or search existing Q&As.
0

Your selectTab function needs to be necessarily bound to the click event on those list elements. There's no other way you can do it. Your code is good enough. You can simplify things using JQuery as well, as some other answer here points out.

Okay, do this:

In your HTML, add "tab" class to each of the tags.

<li class="selected"><a class="tab" href="#div1">DIV1</a></li>
<li class><a class="tab" href="#div2">DIV2</a></li>
<li class><a class="tab" href="#div3">DIV3</a></li>

In your jquery,

$('.tab').click(function(){
var displaydiv = $(this).attr('href');
$('#div1').hide();
$('#div2').hide();
$('#div3').hide();
$(this).show();
$('"'+displaydiv+'"').show();
$(this).parent().attr('class','selected');
})

4 Comments

The problem is how to change the "selected" class name on the corrispondent <li>. I can't find a way.
Ok I gt it working with Javascript only, as I would not like to use JQuery. But I will give it a try :) Look above for my solution.
If you got the a-tag, you can get to the li-tag using the .parentNode property.
What do you think this means? $(this).parent().attr('class','selected');
0
<ul id="tabs">
    <li class="selected"><a onclick="showTab(this);" href="#div1">DIV1</a></li>
    <li><a onclick="showTab(this);" href="#div2">DIV2</a></li>
    <li><a onclick="showTab(this);" href="#div3">DIV3</a></li>
</ul>
<div id="tabs_content">
    <div id="div1" style="display: block;"><textarea name="div1" rows="7" cols="108"></textarea></div>
    <div id="div2" style="display: none;"><textarea name="div2" rows="7" cols="108"></textarea></div>
    <div id="div3" style="display: none;"><textarea name="div3" rows="7" cols="108"></textarea></div>
</div>

Use the following javascript:

function showTab(a)
{
    var id = a.href.replace('#','');
    var tabs = document.getElementById('tabs_content').getElementsByTagName('div');
    var index = -1;
    for(var i=0,n=tabs.length;i<n;i+=1)
    {
        var t = tabs[i];
        if(t.id === id)
        {
            t.style.display = 'block';
            index = i;
        }
        else
        {
            t.style.display = 'none';
        }
    }
    var links = document.getElementById('tabs').getElementsByTagName('li');
    for(var i=0,n=links.length;i<n;i+=1)
    {
        links[i].setAttribute('class', index === i ? 'selected' : '');
    }
}

Of course you could also first cache your menu and tabs, that way you can keep a variable. This is the proper way:

function Menu()
{
    var self = this;
    self.links = document.getElementById('tabs').getElementsByTagName('a');
    self.tabs = document.getElementById('tabs_content').getElementsByTagName('div');
    self.selectedIndex = 0;
    self.n = self.links.length;

    for(var i=0;i<self.n;i+=1)
    {
        // Set onclick for every link in the tabs-menu
        self.links[i].onclick = function(ind){return function(){self.update(ind);};}(i);
    }

    self.update = function(ind)
    {
        // Hide previous tab
        self.links[self.selectedIndex].parentNode.setAttribute('class', '');
        self.tabs[self.selectedIndex].style.display = 'none';

        // Select and show clicked tab
        self.selectedIndex = ind;
        self.links[self.selectedIndex].parentNode.setAttribute('class', 'selected');
        self.tabs[self.selectedIndex].style.display = 'block';
    };
}
setTimeout(function(){new Menu();},1);

Check out the jsfiddle for the Menu class in action: http://jsfiddle.net/3vf4A/1/. Note that even if Javascript is disabled, the a-tag will still get you to the correct area by scrolling to it automatically.

2 Comments

Such a really long Javascript is too long to be simple
The Menu-class is just more than double the size of your jQuery solution. However, it handles the switching less brutal and the performance should be way higher. And even though it takes some extra code, using a bit of OOP it still remains quite maintainable and easy to read.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.