Expand / Collapse JavaScript

Hi,

Do you know how I can change the following JavaScript example so the link is '+' when it is collapsed, and '-' when it is expanded?

I also can´t seem to add more div content ('One' only shows when I click the link, not 'Two').

<html>
<head>
<script>
function showhide(id){
if (document.getElementById){
obj = document.getElementById(id);
if (obj.style.display == "none"){
obj.style.display = "";
} else {
obj.style.display = "none";
}
}
}

</script>
</head>

<body>

<a href="#" onclick="showhide('1'); return(false);">+</a>

<div id="1" style="display: none;">One.</div>
<div id="1" style="display: none;">Two.</div>

</body></html>
GsteingrAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

RoonaanCommented:
Hi,

You cannot use a <div id="1" twice. id is an unique identifier, and should be used as such.

For your code, how about this:

<div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>

  <div id="1a" class="whenOpened" style="display: none;">One.</div>
  <div id="1b" style="whenOpened" display: none;">Two.</div>
</div>

This requires two additional CSS lines though:
.closed .whenOpened {display:none;}
.opened .whenClosed {display:none;}

-r-
Ivo StoykovCommented:
Hello Gsteingr,

<html>
<head>
<script>
function showhide(id)
{
  if (document.getElementById)
  {
    obj = document.getElementById(id);
    if (obj.style.display == "none")
    {
      obj.style.display = "";
      event.srcElement.innerText = "-";
    }
    else
    {
      obj.style.display = "none";
      event.srcElement.innerText = "+";
    }
  }
}

</script>
</head>

<body>

<a href="#" onclick="showhide('1'); return(false);">+</a>

<div id="1" style="display: none;">One.</div>
<div id="1" style="display: none;">Two.</div>

</body></html>


HTH

I
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

callrsCommented:
<html>
<head>
<script>
function showhide(id){
if (document.getElementById){
      obj = document.getElementById(id);
      if (obj.style.display == "none"){
            obj.style.display = "";
            document.getElementById('a').innerHTML="-"
            }
      else {obj.style.display = "none";
            document.getElementById('a').innerHTML="+"
            }
      }
}

</script>
</head>

<body>

<a id="a" href="#" onclick="showhide('1');showhide('2'); return(false);">+</a>

<div id="1" style="display: none;">One.</div>
<div id="2" style="display: none;">Two.</div>

</body></html>

GsteingrAuthor Commented:

If I copy/paste this code into FrontPage it seems to work.

However, a hyperlink with a unuque text must be put inside multiple table cells, but I haven´t been able to make it work yet from your previous examples (f.e.x expanding the link in row nr. 3 or 4 always collapses/expands the nr. 1 text in the table cell.
<table>
<tr><td>Some Text</td></tr>
<tr><td>More Text</td></tr>
</table>

Does anybody know how to fix this?

Thanks a lot for all your help! :-)
GsteingrAuthor Commented:
I think I solved it by giving each a different id number.

My last question is this:
How can let the '+' sign be in front of the Text that you don´t want to move.

F.ex:
+ 'Text that you don´t want to move down when the + hyperlink is expanded'

Thanks a lot!
RoonaanCommented:
You can put the text you don't want to change inside your javascript as well.

-r-
GsteingrAuthor Commented:

callrs: Your solution worked almost. Since my table is rather big and Im using the row number as a name for the link (instead of 'a') I changed your javascript code:
function showhide(id){
if (document.getElementById){
     obj = document.getElementById(id);
     if (obj.style.display == "none"){
          obj.style.display = "";
          document.getElementById('id').innerHTML="-"
          }
     else {obj.style.display = "none";
          document.getElementById('id').innerHTML="+"
          }
     }
}

However I always get the same submenu text for all my table columns with your following code:
<a id="%My_Row_Number%" href="#" onclick="showhide('a');showhide('b'); return(false);">+</a>
<div id="a" style="display: none;">One.</div>
<div id="b" style="display: none;">Two.</div>


ivostoykov: Your s javascript code is pretty generic. However, after putting the link into my table I always get only the '+' sign (I never see the '-' sign when the list collapses). Still it works when I try your example in frontpage. Strange.
GsteingrAuthor Commented:
Roonaan: I tried your css code and it works well.

However I really want to have the plus in front of MyTitle and MyTitle to be left alone when the '+' expands.

If I include MyTitle inside your DIV I get:
+  MyTitle

When I click the '+' sign:      
-
SubItem1
SubItem2
MyTitle

Any idea how to fix this?

Thanks alot!!! :-)
GsteingrAuthor Commented:

Roonaan: One last thing. Do you know how to make Expand All / Collapse All with your CSS?
RoonaanCommented:
You can use multiple links ofcourse:

<tr>
  <td style="width:50px;">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
  </td>
  <td>
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">Title</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">Title</a>
  </td>
</tr>


Expand/Collapse All:
You would have to go through all divs and set them to closed/unclosed.

If all your divs are inside the same parentdivs you can use a

function setAll(state) {
  var div = document.getElementById('div');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}

-r-
GsteingrAuthor Commented:
Roonaan: This is great, but I really don´t want the Title to be a hyperlink (just simple text).

To see what I'm trying to do:
http://www.simaskra.is/

and type f.ex. in the textbox:
gunnar
RoonaanCommented:
Ah, then you can just have:

  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
  Title

  <div class="whenOpened">

-r-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
GsteingrAuthor Commented:

This works now perfectly! Thank you so much Roonaan :-)

You´re obviously very good in CSS. My hat goes down for you.
GsteingrAuthor Commented:
Roonaan:
function setAll(state) {
  var div = document.getElementById('div');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}

I only get this to work with Contacting all the Titles (not expanding them):

<a href="" onclick="toggledDisplay('opened')">Expand All</a> | <a href="" onclick="toggledDisplay('closed')">Contact All</a>
GsteingrAuthor Commented:
The whole example is here. Still can´t get the Expand All and Collapse all work:


<html>
<head>
<title>+ - SomeTitle</title>

  <style type="text/css">
      .closed .whenOpened {display:none;}
      .opened .whenClosed {display:none;}
  </style>
 
  <script>
  function setAll(state) {
  var div = document.getElementById('div');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}
</script>

</head>

<body>
<div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
SomeTitle

  <div id="1" class="whenOpened">One.</div>
  <div id="2" class="whenOpened">Two.</div>
</div>
</body>

<a href="" onclick="setAll('opened')">Expand All</a> | <a href="" onclick="setAll('closed')">Contact All</a>
</html>
RoonaanCommented:
Hi,

The example is build such that you have a div containing all expandable divs. You then give that div an id:

<div id="div">
   <div class="closed">
   ..
  ..
  </div>
   <div class="closed">
   ..
  ..
  </div>
   <div class="closed">
   ..
  ..
  </div>
   <div class="closed">
   ..
  ..
  </div>
</div>

Then you can use the expand all script.

-r-
GsteingrAuthor Commented:

I´m still getting some very strange behaviour when using Expand All / Collapse All inside a Table:

<html>
<head>
<title>SomeTitle</title>

  <style type="text/css">
      .closed .whenOpened {display:none;}
      .opened .whenClosed {display:none;}
  </style>
 
  <script>
  function setAll(state) {
  var div = document.getElementById('div');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}
</script>

</head>

<body>


<div id="div">

      

<table>
      <tr>
            <td><div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
      SomeTitle1
  <div id="1" class="whenOpened">One.</div>
  <div id="2" class="whenOpened">Two.</div>
</div></td>
      </tr>
      
      <tr><td><div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
      SomeTitle2
  <div id="3" class="whenOpened">Three.</div>
  <div id="4" class="whenOpened">Four.</div>
</div></td>
      </tr>
</table>

</div>

<a href="" onclick="setAll('opened')">Expand All</a> | <a href="" onclick="setAll('closed')">Contact All</a>

</body>
</html>
RoonaanCommented:
That is because it traverses only direct childs of the <div id="div">.

Also make sure to add return:false at the end of your setAll call:

<a href="" onclick="setAll('opened');return false;">Expand All</a> | <a href="" onclick="setAll('closed');return false">Contact All</a>

For an extensive example on using this setup with tables see:
http://www.roonaan.nl/lib/css/view/css.collapse.inc.html

Using that code you can give the table an id and put that same id in the "var div = document.getElementById('div');" of the setState function, as the tbody's are direct childs of the table tag.

-r-
GsteingrAuthor Commented:

I googled some parent-child examples in css.

I still can´t find out why Expand All / Collapse All doesn´t work:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
 <head>
   <style type="text/css">
   .opened .whenclosed {display:none;}
   .closed .whenopened {display:none;}
   </style>
   <script type="text/javascript">

   function getParentElement(elem, searchtag)
   {
     while(elem.tagName.toLowerCase() != searchtag)
     {
       if(!elem.parentNode)
         return false;
       elem = elem.parentNode;
     }
     return elem;
   }
   
  function setAll(state) {
  var div = document.getElementById('closed');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}
   </script>
 </head>
 <body>
 
   <table>
   <div id="div">
   
     <tbody class="closed">
       <tr>
         <td>
           <a href="#open"  class="whenclosed" onclick="getParentElement(this, 'tbody').className='opened';return false;">Uncollapse</a>
           <a href="#close" class="whenopened" onclick="getParentElement(this, 'tbody').className='closed';return false;">Collapse</a>
         </td>
       </tr>
       <tr class="whenopened">
         <td>1: This element shows only when opened</td>
       </tr>
     </tbody>
     
     <tbody class="closed">
       <tr>
         <td>
           <a href="#open"  class="whenclosed" onclick="getParentElement(this, 'tbody').className='opened';return false;">Uncollapse</a>
           <a href="#close" class="whenopened" onclick="getParentElement(this, 'tbody').className='closed';return false;">Collapse</a>
         </td>
       </tr>
       <tr class="whenopened">
         <td>2: This element shows only when opened</td>
       </tr>
     </tbody>
     
      </div>
   </table>
   
<a href="" onclick="setAll('opened');return false;">Expand All</a> | <a href="" onclick="setAll('closed');return false">Contact All</a>
   
 </body>
</html>
GsteingrAuthor Commented:

I got some of the Collapse All to work, but it only collapses the first element in the table. I haven't been successful in making Expand All work though.

--------------------------
<html>
<head>
<title>SomeTitle</title>

  <style type="text/css">
      .closed .whenOpened {display:none;}
      .opened .whenClosed {display:none;}
  </style>
 
  <script>
  function setAll(state) {
  var div = document.getElementById('div');
  for(i = 0; i < div.childNodes.length; i++) {
    if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
  }
}
</script>

</head>

<body>








      <table>
      
      
<tr><td>
<div id="div">
                        
<div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
  <div id="1a" class="whenOpened">One.</div>
  <div id="1b" class="whenOpened">Two.</div>
</div>
                  
            
      
</td></tr>
<tr><td>


                        
<div class="closed">
  <a class="whenClosed" href="#" onclick="this.parentNode.className='opened';return false;">+</a>
  <a class="whenOpened" href="#" onclick="this.parentNode.className='closed';return false;">-</a>
  <div id="1c" class="whenOpened">Three.</div>
  <div id="1d" class="whenOpened">Four.</div>
</div>
                  
</div>      

</td></tr></table>



<a href="" onclick="setAll('opened');return true;">Expand All</a> | <a href="" onclick="setAll('closed');return false">Contact All</a>

</body>
</html>

RoonaanCommented:
You can use this:

<html>
<head>
<title>SomeTitle</title>

  <style type="text/css">
     .closed .whenOpened {display:none;}
     .opened .whenClosed {display:none;}
  </style>
 
  <script>
  function setAll(state) {
    var div = document.getElementById('myTable');
    for(i = 0; i < div.childNodes.length; i++) {
      if(div.childNodes[i].nodeType == 1) div.childNodes[i].className = state;
    }
  }
  function getParentElement(elem, tag) {
    tag = tag.toLowerCase();
    while(elem && elem.nodeName.toLowerCase() != tag) {
      if(!elem.parentNode) {
        return null;
      }
      elem = elem.parentNode;
    }
    return elem;
  }
</script>

</head>

<body>








<table id="myTable">
  <tbody class="closed">
    <tr><td>
      <a class="whenClosed" href="#" onclick="getParentElement(this,'tbody').className='opened';return false;">+</a>
      <a class="whenOpened" href="#" onclick="getParentElement(this,'tbody').className='closed';return false;">-</a>
      <div id="1a" class="whenOpened">One.</div>
      <div id="1b" class="whenOpened">Two.</div>
    </td></tr>
  </tbody>
  <tbody class="closed">
    <tr><td>
      <a class="whenClosed" href="#" onclick="getParentElement(this,'tbody').className='opened';return false;">+</a>
      <a class="whenOpened" href="#" onclick="getParentElement(this,'tbody').className='closed';return false;">-</a>
      <div id="1a" class="whenOpened">One.</div>
      <div id="1b" class="whenOpened">Two.</div>
    </td></tr>
  </tbody>
  <tbody class="closed">
    <tr><td>
      <a class="whenClosed" href="#" onclick="getParentElement(this,'tbody').className='opened';return false;">+</a>
      <a class="whenOpened" href="#" onclick="getParentElement(this,'tbody').className='closed';return false;">-</a>
      <div id="1a" class="whenOpened">One.</div>
      <div id="1b" class="whenOpened">Two.</div>
    </td></tr>
  </tbody>
</table>



<a href="" onclick="setAll('opened');return false;">Expand All</a> | <a href="" onclick="setAll('closed');return false">Contact All</a>

</body>
</html>
GsteingrAuthor Commented:
You´re a genious! Thanks a lot!! :)
RoonaanCommented:
Not yet a genious, need a couple of points to get to that status ;-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Web Development Software

From novice to tech pro — start learning today.