Link to home
Start Free TrialLog in
Avatar of Gsteingr
Gsteingr

asked on

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>
Avatar of Swapnil
Swapnil
Flag of India image

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-
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
Avatar of callrs
callrs

<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>

Avatar of Gsteingr

ASKER


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! :-)
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!
You can put the text you don't want to change inside your javascript as well.

-r-

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.
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!!! :-)

Roonaan: One last thing. Do you know how to make Expand All / Collapse All with your CSS?
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-
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
ASKER CERTIFIED SOLUTION
Avatar of Roonaan
Roonaan
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

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

You´re obviously very good in CSS. My hat goes down for you.
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>
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>
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-

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>
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-

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>

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>

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>
You´re a genious! Thanks a lot!! :)
Not yet a genious, need a couple of points to get to that status ;-)