Hi there. I'm trying to figure out how to make this JS work with nested divs. Right now it looks for TagName 'div'. I have multiple nested divs and that seems to mess things up pretty good. I'm not sure how to add more detail to this code, like look for specific ID's instead of a global div tag.....
Here's the code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Toggle Div Display</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">

    var articleIndex = [];
    var articleLinks = "";
    var articles = "";
    var prevArticle = "";   
    var prevClicked = "";
    var inactiveColor = "#add8e6";
    var activeColor = "#ff69b4";

    function toggle(currArticle){

        if (prevArticle !== "")
            {                            
             articles[prevArticle].className = "toggleHide";
            }       
        for (i=0; i<articleLinks.length; i++)
            {
             if (articleLinks[i] == currArticle)
                {
                 articles[i].className = "toggleShow";
                 prevArticle = i;               
                }
            }       
    }

    function init(){

        articleLinks = document.getElementsByTagName('a');
        articles = document.getElementById('articleContainer').getElementsByTagName('div');
        for (i=0; i<articleLinks.length; i++)
            {
             if (articleLinks[i].className == "articleLink")
                {
                 articleIndex[articleIndex.length] = articleLinks[i];
                 articleLinks[i].onclick = function()
                    {   
                     if (prevClicked != "")
                        {
                         prevClicked.style.color = inactiveColor;
                        }   
                     this.style.color = activeColor;
                     prevClicked = this;                     
                     toggle(this);
                     return false;
                    }   ;            
                }
            }       
    }

    navigator.appName == "Microsoft Internet Explorer" ? attachEvent('onload', init, false) : addEventListener('load', init, false);    

</script>
<style type="text/css">

     body {margin-top: 50px;}
    .articleLink {color: #add8e6; text-decoration: none; margin-left: 10px; margin-right: 10px;}
    .toggleHide {display: none;}    
    .toggleShow {display: block; font-family: arial; font-size: 12pt; background-color: #f0fff0; width: 150px;
             height: 100px; padding: 3px;}

</style>
</head>
    <body>

        <a href="#" class="articleLink"> Show Article 1 </a>
        <a href="#" class="articleLink"> Show Article 2 </a>
        <a href="#" class="articleLink"> Show Article 3 </a>      

        <br><br>

        <div id="articleContainer">
            <div class="toggleHide"> 1st </div>
            <div class="toggleHide">2nd
                    <div>nested div is a problem, delete this div and it works....but I have multiple nested divs.</div>
            </div>
            <div class="toggleHide"> This is article 3 </div>
        </div>

    </body>
</html>

Recommended Answers

All 9 Replies

Could you please use the 'code' tag on the top of the box you are posting? It is very difficult to read your code in plain text.

<a href="#" class="articleLink"> Show Article 1 </a>
<a href="#" class="articleLink"> Show Article 2 </a>
<a href="#" class="articleLink"> Show Article 3 </a>

The code above is not easy to maintain. Using getElementsByTagName() could cause problem easily when you want to add/remove certain element which has the tag name you are manipulating with. The function will grab all tag name elements regardless they are child or parent nodes, but as long as they are child nodes of the caller, they are included. In your code, you have exactly the same class & properties for all of your tags but the content inside. In other words, you have no clear way to identify which link matches with which div; as a result, it is more difficult to deal with nested (child nodes) elements. I could help you solve the problem, but this would not be a good practice for you in the future. Do you want to just show/hide a div (when one is clicked, the previous clicked one is hide)? Does all of them have to look like a link? Is this page dynamic or static?

You could set an attribute of each of the anchor's that indicate which article to show (since you already know how many links and articles you have. Then give each containing div a corresponding id. Then you will need to pass the triggering anchor to the onclick event handler. Then in your onclick function you would still grab all the article divs but you would hide all but the one that has the corresponding id to the attribute on the link that was clicked. I would also add a name attribute to each set of elements and use document.getElementsByName rather than tagname so that you can separate types a little better.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Toggle Div Display</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
var articleIndex = [];
var articleLinks = "";
var articles = "";
var prevArticle = "";	
var prevClicked = "";
var inactiveColor = "#add8e6";
var activeColor = "#ff69b4";

function handleClick(id)
{
   
   var articles = document.getElementsByName("articles");
   for(var i = 0; i < articles.length; i++)
   {
      if(articles[i].id == id)
      {
          articles[i].className = "toggleShow";
      }else{
          articles[i].className = "toggleHide";
      }
   }
}
function init(){

   articleLinks = document.getElementsByName('articleLink');
console.log("link",articleLinks);
   articles = document.getElementsByName("articles");
   for (i=0; i<articleLinks.length; i++)
   {
      articleLinks[i].onclick = function(){
          handleClick(this.getAttribute("divId"));
      };
    }	
}


</script>
<style type="text/css">

body {margin-top: 50px;}
.articleLink {color: #add8e6; text-decoration: none; margin-left: 10px; margin-right: 10px;}
.toggleHide {display: none;}	
.toggleShow {display: block; font-family: arial; font-size: 12pt; background-color: #f0fff0; width: 150px;
height: 100px; padding: 3px;}

</style>
</head>
<body onload="init();">

<a href="#" name="articleLink" divId="art1" class="articleLink"> Show Article 1 </a>
<a href="#" name="articleLink" divId="art2" class="articleLink"> Show Article 2 </a>
<a href="#" name="articleLink" divId="art3" class="articleLink"> Show Article 3 </a>	

<br><br>

<div id="articleContainer">
   <div id=art1 name="articles" class="toggleHide"> 1st </div>
   <div id=art2 name="articles" class="toggleHide">2nd
      <div>
         nested div is a problem</div>
      </div>
   <div id=art3 name="articles" class="toggleHide"> This is article 3 </div>
</div>

</body>
</html>

Thanks scrappedcola! I gave this a try and I'm getting an error that 'console' is undefined.

You could set an attribute of each of the anchor's that indicate which article to show (since you already know how many links and articles you have. Then give each containing div a corresponding id. Then you will need to pass the triggering anchor to the onclick event handler. Then in your onclick function you would still grab all the article divs but you would hide all but the one that has the corresponding id to the attribute on the link that was clicked. I would also add a name attribute to each set of elements and use document.getElementsByName rather than tagname so that you can separate types a little better.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Toggle Div Display</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
var articleIndex = [];
var articleLinks = "";
var articles = "";
var prevArticle = "";	
var prevClicked = "";
var inactiveColor = "#add8e6";
var activeColor = "#ff69b4";

function handleClick(id)
{
   
   var articles = document.getElementsByName("articles");
   for(var i = 0; i < articles.length; i++)
   {
      if(articles[i].id == id)
      {
          articles[i].className = "toggleShow";
      }else{
          articles[i].className = "toggleHide";
      }
   }
}
function init(){

   articleLinks = document.getElementsByName('articleLink');
console.log("link",articleLinks);
   articles = document.getElementsByName("articles");
   for (i=0; i<articleLinks.length; i++)
   {
      articleLinks[i].onclick = function(){
          handleClick(this.getAttribute("divId"));
      };
    }	
}


</script>
<style type="text/css">

body {margin-top: 50px;}
.articleLink {color: #add8e6; text-decoration: none; margin-left: 10px; margin-right: 10px;}
.toggleHide {display: none;}	
.toggleShow {display: block; font-family: arial; font-size: 12pt; background-color: #f0fff0; width: 150px;
height: 100px; padding: 3px;}

</style>
</head>
<body onload="init();">

<a href="#" name="articleLink" divId="art1" class="articleLink"> Show Article 1 </a>
<a href="#" name="articleLink" divId="art2" class="articleLink"> Show Article 2 </a>
<a href="#" name="articleLink" divId="art3" class="articleLink"> Show Article 3 </a>	

<br><br>

<div id="articleContainer">
   <div id=art1 name="articles" class="toggleHide"> 1st </div>
   <div id=art2 name="articles" class="toggleHide">2nd
      <div>
         nested div is a problem</div>
      </div>
   <div id=art3 name="articles" class="toggleHide"> This is article 3 </div>
</div>

</body>
</html>

Hi Taywin,
Sorry about that - I thought I had added the code-tags, but I must be doing it wrong. :(
To answer your questions.....This is a static page with multiple div tags and links.
I do want the the menu links to show/hide div onclick, and I also have links within nested divs that need to show/hide. So I need unique id's to swap instead of triggering from just a 'div' tag.

Here's an example of a menu link with a nested div with links:
(classes and id's based on my old DivSwap js file)

<!--MEET-->
<div class="detail" id="meet" style="background: url(photos/team_ricky.jpg) no-repeat center top; height: 514px; width: 744px;">
<div onclick="reveal('meet_ricky');" style="display: inline; text-align: right; margin: 20px 0 0 510px;"><a class="current" href="#">RICHARD</a> | </div>
<div onclick="reveal('meet_tony');" style="display: inline; text-align: right;"><a class="red" href="#">TONY</a>  |  </div>
<div onclick="reveal('meet_anthony');" style="display: inline; text-align: right;"><a class="red" href="#">ANTHONY</a>  |   </div>
<div onclick="reveal('meet_jose');" style="display: inline; text-align: right;"><a class="red" href="#">JOSE</a> </div>
<div class="grey" style="margin: 1px auto 0 508px;"><p><br /><br /><span style="color: #bd3a2d;">"</span>Quote here about something<span style="color: #bd3a2d;">"</span></p> <br />
<p style="font-weight: normal;"><span style="color: #bd3a2d;"><strong>Background:</strong></span> <span style="font-size: 93%;">Rick has been involved in the motorcycle community for over 20 years.  Riding a bike since he was 15, he started going to track days over nine years ago.  He is also a certified Motorcycle Safety Instructor.  Rick is currently employed as a motorcycle mechanic in San Jose. This is Rick's fourth year competing in the AFM racing organization.</span></p>&nbsp;
<p style="font-weight: normal;"><span style="color: #bd3a2d;"><strong>AFM#:</strong></span> <span style="font-size: 93%;">213</span></p>
<p style="font-weight: normal;"><span style="color: #bd3a2d;"><strong>Class:</strong></span> <span style="font-size: 93%;">Expert</span></p>
<p style="font-weight: normal;"><span style="color: #bd3a2d;"><strong>Race Bike:</strong></span> <span style="font-size: 93%;">'07 Suzuki GSXR 600</span></p>
<p style="font-weight: normal;"><span style="color: #bd3a2d;"><strong>Residence:</strong></span> <span style="font-size: 93%;">San Jose, CA</span></p>
</div>
</div>

Could you please use the 'code' tag on the top of the box you are posting? It is very difficult to read your code in plain text.
<a href="#" class="articleLink"> Show Article 1 </a>
<a href="#" class="articleLink"> Show Article 2 </a>
<a href="#" class="articleLink"> Show Article 3 </a>

The code above is not easy to maintain. Using getElementsByTagName() could cause problem easily when you want to add/remove certain element which has the tag name you are manipulating with. The function will grab all tag name elements regardless they are child or parent nodes, but as long as they are child nodes of the caller, they are included. In your code, you have exactly the same class & properties for all of your tags but the content inside. In other words, you have no clear way to identify which link matches with which div; as a result, it is more difficult to deal with nested (child nodes) elements. I could help you solve the problem, but this would not be a good practice for you in the future. Do you want to just show/hide a div (when one is clicked, the previous clicked one is hide)? Does all of them have to look like a link? Is this page dynamic or static?

Thanks scrappedcola! I gave this a try and I'm getting an error that 'console' is undefined.

Sorry just remove the console its just used in FF and IE7+ (with developer tools) to print out debug info.

Sorry just remove the console its just used in FF and IE7+ (with developer tools) to print out debug info.

Ah yes ok just commented it out and it works now. The only thing I'm missing from the original js is the active font color change. Only one menu link has the "active" color, then when any other menu link is clicked, that changes back and the clicked link turns the "active" color.
I'm not smart enough to try to code that. :(

The reason all links changed color because your href of all links are the same (href="#"). Unless you give the href different value, you would have this problem no matter what. You could, however, use CSS to imitate 'a' tag display and manipulate it with JavaScript (onclick()).

Below is an example to show you how to imitate 'a' tag using CSS.

<style type="text/css">
.link_fresh {
  text-decoration: underline;
  color: blue;
  cursor: hand;
  cursor: pointer;
}
.link_visited {
  text-decoration: underline;
  color: #F0F0E0;
  cursor: hand;
  cursor: pointer;
}
</style>

<script type="text/javascript">
function activateLink(obj) {
  obj.className = obj.className.replace("link_fresh", "link_visited")
  // do something else such as display stuff you want to display
}
</script>

<div id="artical1" class="link_fresh" onclick="activateLink(this)">Show Article 1</div>
<div id="artical2" class="link_fresh" onclick="activateLink(this)">Show Article 2</div>
<div id="artical3" class="link_fresh" onclick="activateLink(this)">Show Article 3</div>

function activateLink(obj) {
obj.className = obj.className.replace("link_fresh", "link_visited")
// do something else such as display stuff you want to display
}

That only toggles one object.
You need to cycle through all 'related' objects; something like
if "this" then "set" else "clear".will do the trick.

In one of scrappedcola posts to this thread there is similar code.

@fxm, of course. ;) I am imitating 'a' tag which does not need to toggle anything but its visited color. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.