Link to home
Start Free TrialLog in
Avatar of Kratos101
Kratos101

asked on

Expand All/ Collapse All

All,

I have the following code where categories expand and collapse upon click of the arrow images next to them. The arrow images also change, based on the status of the row. I want to implement a function so that:

1. On click of a link "Expand All/Collpase All", all categories should be expanded or collapsed. Please keep in mind that the respective arrow images also should change accordingly.

Thanks

<html>
<head>

<script src="http://www.google.com/jsapi"></script>

<script>
google.load("jquery", "1.3.2");
google.load("jqueryui", "1.7.2");
</script>

<script language="JavaScript">
function toggleTableRows()
{
  $(document).ready(function() {


    $('img.parent')
      .css("cursor","pointer")
      .toggle(
        function() {
          $(this).attr("title","Click to Expand")
          $(this).attr("src","arrow_collapsed.gif");
          $('tr').siblings('#child-'+this.id).toggle();
        },
        function() {
          $(this).attr("title","Click to Collapse");
          $(this).attr("src","arrow_expanded.gif");
          $('tr').siblings('#child-'+this.id).toggle();
        }
      ); 
    initCheckBoxes("frmDinnerMenu");


  });

} 
function toggleCheckboxes(current, form, field) {
  $(document).ready(function() {
    $("#"+ form +" :checkbox[name^='"+ field +"[']")
      .attr("checked", current.checked);
  });
} 
function toggleParentCheckboxes(current, form) {
  var totalCheckboxes = $("#"+ form +" :checkbox[name='"+ current.name +"']").length;
  var numChecked = $("#"+ form +" :checkbox[name='"+ current.name +"']:checked").length;
  var checked = (totalCheckboxes == numChecked );
    if(numChecked !=0 && (totalCheckboxes!=numChecked))
	{
	       $("#"+ form +" :checkbox[name='chk"+ current.name.match(/(\d+)/)[1] +"']").css({"opacity":"0.3"});
	}
	else
	{
	       $("#"+ form +" :checkbox[name='chk"+ current.name.match(/(\d+)/)[1] +"']").css({"opacity":"100"});
	}
  // replace '[anything]' with '' instead of just '[]'
  $("#"+ form +" :checkbox[name='"+ current.name.replace(/\[[^\]]*\]/, "") +"']")
    .attr("checked", checked);
} 
function initCheckBoxes(form) {
  $("#"+ form +" :checkbox:checked").each(function() {
    if (this.name.match(/chk[0-9]\[.*\]/)) {
      toggleParentCheckboxes(this, form);
    }
  });
}
</script>
<script language="JavaScript">toggleTableRows();</script>
<style type="text/css">tr.c1 {display: none;}</style>
</head>
<body>

<form name="frmDinnerMenu" id="frmDinnerMenu" method="POST" action="">
<table border=1>
<tr>
    <td><img class="parent" id="0" src="arrow_collapsed.gif" title="Click to Expand">Category - Fruits</td>
    <td><input type="checkbox" name="chk0" onclick="toggleCheckboxes(this, 'frmDinnerMenu', 'chk0');"/></td>
</tr>
<tr class="c1" id="child-0">
    <td>Apple</td>
    <td><input type="checkbox" value="true" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1" id="child-0">
    <td>Banana</td>
    <td><input type="checkbox" value="false" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1" id="child-0">
    <td>Orange</td>
    <td><input type="checkbox" checked value="true" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr>
    <td><img class="parent" id="1" src="arrow_collapsed.gif" title="Click to Expand">Category - Vegetables</td>
    <td><input type="checkbox" name="chk1" onclick="toggleCheckboxes(this, 'frmDinnerMenu', 'chk1');"/></td>
</tr>
<tr class="c1" id="child-1">
    <td>Eggplant</td>
    <td><input type="checkbox" value="true" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1" id="child-1">
    <td>Tomato</td>
    <td><input type="checkbox" value="false" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1" id="child-1">
    <td>Cabbage</td>
    <td><input type="checkbox" checked value="true" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
</table>
</form>
</body>
</html>

Open in new window

arrow-collapsed.gif
arrow-expanded.gif
Avatar of David H.H.Lee
David H.H.Lee
Flag of Malaysia image

Hi Kratos101,
Re-order your existing toggle code, that should solve the problem.
$('img.parent')
      .css("cursor","pointer")
      .toggle(
        function() {
          $(this).attr("title","Click to Collapse");
          $(this).attr("src","arrow_expanded.gif");
          $('tr').siblings('#child-'+this.id).toggle();
        },
        function() {
          $(this).attr("title","Click to Expand")
          $(this).attr("src","arrow_collapsed.gif");
          $('tr').siblings('#child-'+this.id).toggle();
        }
      ); 

Open in new window

Avatar of Kratos101
Kratos101

ASKER

Sorry.. it's not working that way...  Can you please check  the question again?
you are developing "design habits" that will lead to headaches down the road, specifically:
>> <tr class="c1" id="child-0">
You have multiple elements with id="child-0". The same goes for id="child-1". You are only allowed to have UNIQUE ids per page. So you can only have ONE item with id="child-0". What you CAN have multiple times are classes. Furthermore you CAN have multiple classes per element. So instead of:
<tr class="c1" id="child-0">

use:
<tr class="c1 child-0">


The corrected code is below:

<html>
<head>

<script src="http://www.google.com/jsapi"></script>

<script>
google.load("jquery", "1.3.2");
google.load("jqueryui", "1.7.2");
</script>

<script language="JavaScript">
function toggleTableRows()
{
  $(document).ready(function() {


    $('img.parent')
      .css("cursor","pointer")
      .toggle(
        function() {
          $(this).attr("title","Click to Expand")
          $(this).attr("src","arrow_collapsed.gif");
          $('tr').siblings('.child-'+this.id).toggle();
        },
        function() {
          $(this).attr("title","Click to Collapse");
          $(this).attr("src","arrow_expanded.gif");
          $('tr').siblings('.child-'+this.id).toggle();
        }
      ); 
    initCheckBoxes("frmDinnerMenu");


  });

} 
function toggleCheckboxes(current, form, field) {
  $(document).ready(function() {
    $("#"+ form +" :checkbox[name^='"+ field +"[']")
      .attr("checked", current.checked);
  });
} 
function toggleParentCheckboxes(current, form) {
  var totalCheckboxes = $("#"+ form +" :checkbox[name='"+ current.name +"']").length;
  var numChecked = $("#"+ form +" :checkbox[name='"+ current.name +"']:checked").length;
  var checked = (totalCheckboxes == numChecked );
    if(numChecked !=0 && (totalCheckboxes!=numChecked))
        {
               $("#"+ form +" :checkbox[name='chk"+ current.name.match(/(\d+)/)[1] +"']").parent().css({"opacity":"0.3","background-color":"#aeaeae"});
        }
        else
        {
               $("#"+ form +" :checkbox[name='chk"+ current.name.match(/(\d+)/)[1] +"']").parent().css({"opacity":"100","background-color":"#fff"});
        }
  // replace '[anything]' with '' instead of just '[]'
  $("#"+ form +" :checkbox[name='"+ current.name.replace(/\[[^\]]*\]/, "") +"']")
    .attr("checked", checked);
} 
function initCheckBoxes(form) {
  $("#"+ form +" :checkbox:checked").each(function() {
    if (this.name.match(/chk[0-9]\[.*\]/)) {
      toggleParentCheckboxes(this, form);
    }
  });
}
$(document).ready(
	function(){
		$("#toggler").bind("click",function(){
			if(this.innerHTML.indexOf("Expand")!=-1)
			{
				$("img.parent").each(function( index, item){
					item.src="arrow_expanded.gif";
					$("tr.child-"+item.id).show();
				});
				this.innerHTML="Collapse All";
			}
			else
			{
				$("img.parent").each(function( index, item){
					item.src="arrow_collapsed.gif";
					$("tr.child-"+item.id).hide();
				});
				this.innerHTML="Expand All";
			}
		});
	}
);
</script>
<script language="JavaScript">toggleTableRows();</script>
<style type="text/css">tr.c1 {display: none;}</style>
</head>
<body>
<a href="#" id="toggler">Expand All</a>
<form name="frmDinnerMenu" id="frmDinnerMenu" method="POST" action="">
<table border=1>
<tr>
    <td><img class="parent" id="0" src="arrow_collapsed.gif" title="Click to Expand">Category - Fruits</td>
    <td><input type="checkbox" name="chk0" onclick="toggleCheckboxes(this, 'frmDinnerMenu', 'chk0');"/></td>
</tr>
<tr class="c1 child-0">
    <td>Apple</td>
    <td><input type="checkbox" value="true" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1 child-0">
    <td>Banana</td>
    <td><input type="checkbox" value="false" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1 child-0">
    <td>Orange</td>
    <td><input type="checkbox" checked value="true" name="chk0[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr>
    <td><img class="parent" id="1" src="arrow_collapsed.gif" title="Click to Expand">Category - Vegetables</td>
    <td><input type="checkbox" name="chk1" onclick="toggleCheckboxes(this, 'frmDinnerMenu', 'chk1');"/></td>
</tr>
<tr class="c1 child-1">
    <td>Eggplant</td>
    <td><input type="checkbox" value="true" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1 child-1">
    <td>Tomato</td>
    <td><input type="checkbox" value="false" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
<tr class="c1 child-1">
    <td>Cabbage</td>
    <td><input type="checkbox" checked value="true" name="chk1[]" onclick="toggleParentCheckboxes(this, 'frmDinnerMenu');"/></td>
</tr>
</table>
</form>
</body>
</html>

Open in new window

Thanks Hielo for pointing that out ! The fact is in my original code, I don't use "class="c1" at all.. I have to display alternate row colors and hence had to use something like <tr style="display:none" class="alt" id="child-0"> for even rows and <tr style="display:none" id="child-1"> for odd rows.

I can move style="display:none" to a new css class. I am not sure if this is the best way to do it, but I am using it like this as I know we cannot have two css class attributes for a single element.

Please let me know if I can fix issues like this in a good design manner.

Thanks
>>as I know we cannot have two css class attributes for a single element.
This you CANNOT do:
<td class="c1" class="child-0">...</td>

This you CAN do:
<td class="c1 child-0">...</td>

Noticed that this is what I did on the last segment of code I posted. I also changed the part where you are adding the opacity. Not sure if you missed my last comment on yesterday's problem. To add the color, you need to add it to the TD not to the INPUT itself. Again, notice that all you need to do is add precede the .css(...) with .parent()
Thanks for the comments..
I noticed your comments on opacity in your previous post.. I will take that path...
the code above should be fully functional since I also changed:
$('tr').siblings('#child-'+this.id).toggle();

to:
$('tr').siblings('.child-'+this.id).toggle();

(notice how the # was changed to a dot) since I changed your code to:
<tr class="c1 child-0">

Regards,
Hielo
I noticed one bug in the above code...  Follow these steps to replicate:

1. When the page loads, click "Expand All"..
2. Click "Collapse All".
3. Expand one of the categories by clicking on the arrow next to it.

Notice that the category expands, but the arrow image doesn't change to the expanded image.

How can we fix this?
ASKER CERTIFIED SOLUTION
Avatar of hielo
hielo
Flag of Wallis and Futuna 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
Perfect.. Thanks a bunch for the great work !! I am new to Jquery and am learning as much as possible... Thanks for all the help.. :)
Great work Hielo ! This should be useful to many people !