Hello Everyone,

I created a javascript function to show/hide element id. In the code, the detail row will be show when its header row is clicked and the detail row will be hiiden after the hyperlink is clicked.


Can you give any advice on how to show/hide the detail row whenever its header row is clicked? For example, if I clicked header row #2, it will show detail row #2 and hide detail rows #1 and #3.

Looking forward to your replies.

Thanks in advance.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<script type="text/javascript">
function showHide(currElem,hide){
	if(document.layers){	// Netscape 4+
		dom = document.layers[currElem].style;
	}else if(document.getElementById){	// Netscape 6+, gecko, IE 5+
		dom = document.getElementById(currElem).style;
	}else if(document.all){	// IE 4+
		dom = document.all[currElem].style;
	}else{	// Browser unknown; do nothing
		return ;
	}
	if (hide==1){
		if (dom.display == "" || dom.display == "inline" || dom.display == "block" || dom.display == "table-row"){
			dom.display = "none";
			dom.visibility = "hidden";
		}
	}else{
		dom.display = "";
		dom.visibility = "visible";
	}
}
</script>
</head>

<body>
<table border="1" cellpadding="10">
  <tr>
    <th>&nbsp;</th>
    <th id="r0c1">Column 1</th>
    <th id="r0c2">Column 2</th>
    <th id="r0c3">Column 3</th>
    <th id="r0c4">Column 4</th>
  </tr>
  <tr id="row1" onclick="javascript:showHide('row1_1',0);" style="cursor: pointer;">
    <td><b><a href="javascript:void(0);">Row 1</a></b></td>
    <td id="r1c1">&nbsp;
    <input type="text" name="textfield" /></td>
    <td id="r1c2">&nbsp;
      <input type="text" name="textfield2" /></td>
    <td id="r1c3">&nbsp;
      <input type="text" name="textfield3" /></td>
    <td id="r1c4">&nbsp;
      <input type="text" name="textfield4" /></td>
  </tr>
  <tr id="row1_1" style=" display:none;">
    <td colspan="6">Row 1 details </td>
  </tr>
  <tr id="row2" onclick="javascript:showHide('row2_1',0);" style="cursor: pointer;">
    <td><b><a href="javascript:void(0);">Row 2</a></b></td>
    <td id="r2c1">&nbsp;
      <input type="text" name="textfield5" /></td>
    <td id="r2c2">&nbsp;
      <input type="text" name="textfield6" /></td>
    <td id="r2c3">&nbsp;
      <input type="text" name="textfield7" /></td>
    <td id="r2c4">&nbsp;
      <input type="text" name="textfield8" /></td>
  </tr>
  <tr id="row2_1" style=" display:none;">
    <td colspan="5">Row 2 details </td>
  </tr>
  <tr id="row3" onclick="javascript:showHide('row3_1',0);" style="cursor: pointer;">
    <td><b><a href="javascript:void(0);">Row 3</a></b></td>
    <td id="r3c1">&nbsp;
      <input type="text" name="textfield9" /></td>
    <td id="r3c2">&nbsp;
      <input type="text" name="textfield10" /></td>
    <td id="r3c3">&nbsp;
      <input type="text" name="textfield11" /></td>
    <td id="r3c4">&nbsp;
      <input type="text" name="textfield12" /></td>
  </tr>
  <tr id="row3_1" style=" display:none;">
    <td colspan="5">Row 3 details </td>
  </tr>
</table>
</body>
</html>

Quick fix: just add the two other hides after the show. For example:

onclick="javascript:showHide('row1_1',0);javascript:showHide('row1_2',1);javascript:showHide('row1_3',1)"

Thanks for the reply.

Yes, I can do this what you have suggested. But how can I do this automatically. For example:

If current row clicked then
show details current row;
hide other details row;
End If

Jamojo,

I don't normally encourage people to use a javascript lib but your problem is fairly difficult in standard javascript and very simple in jquery, as you will see below.

I think this is what you want:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
	function details(fn) {
		return function() {
			var r = $(this).closest("tbody").find("tr.detailsRow")[fn]();
			$("tr.detailsRow").not(r).hide();
		};
	};
	$(".detailsRow").hide();
	$detailsButtons = $(".detailsButton").click(details('toggle'));
	$detailsButtons.closest("tr").find("input").click(details('show'));
});
</script>

</head>

<body>
<table border="1" cellpadding="10">
  <tr>
    <th>&nbsp;</th>
    <th>Column 1</th>
    <th>Column 2</th>
    <th>Column 3</th>
    <th>Column 4</th>
  </tr>
  <tbody>
  <tr>
    <td><button class="detailsButton">Row 1 details</button></td>
    <td><input type="text" name="textfield" /></td>
    <td><input type="text" name="textfield2" /></td>
    <td><input type="text" name="textfield3" /></td>
    <td><input type="text" name="textfield4" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 1 details </td>
  </tr>
  </tbody>
  <tbody>
  <tr>
    <td><button class="detailsButton">Row 2 details</button></td>
    <td><input type="text" name="textfield5" /></td>
    <td><input type="text" name="textfield6" /></td>
    <td><input type="text" name="textfield7" /></td>
    <td><input type="text" name="textfield8" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 2 details </td>
  </tr>
  </tbody>
  <tbody>
  <tr>
    <td><button class="detailsButton">Row 3 details</button></td>
    <td><input type="text" name="textfield9" /></td>
    <td><input type="text" name="textfield10" /></td>
    <td><input type="text" name="textfield11" /></td>
    <td><input type="text" name="textfield12" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 3 details </td>
  </tr>
  </tbody>
</table>
</body>
</html>

You will see that I've added <tbody>...</tbody> around each pair of table rows and added classes. Otherwise the HTML is significantly simpler.

The whole thing is controlled by classes not ids. You can add the ids back in if they are necessary for other reasons.

Airshow

Airshow,

Yes, this is what I am trying to accomplish. Now, I changed the button to use an image. Can you please give me suggestion on how to change the toggle button to show button which has a different image source?

Thank you

Jamojo,

I've not tested but it should be something like this:

$(function() {
	function details(fn) {
		return function() {
			var r = $(this).closest("tbody").find("tr.detailsRow")[fn]();
			$("tr.detailsRow").not(r).hide();
			return false;
		};
	};
	$(".detailsRow").hide();
	$detailsButtons = $(".detailsButton").click(details('toggle'));
	$detailsButtons.closest("tr").find("input").click(details('show'));
});
<td><a class="detailsButton" href="#"><img src="mybuttonimage.gif" width="36" height="12" /></a></td>

Note in particular that the function returned by details() now returns false. This suppresses the natural hyperlink action of the <a> tags in which the button images are wrapped. Returning false should have no effect on the other use of details() , where it is attached as the click handler for the input elements.

Airshow

Thanks for the reply. I worked fine to me. Please, give me some suggestion when the image is clicked, a image will be shown or the image source will be changed.

For example, if <img src="expand.gif" /> is clicked then <img src="collapse.gif">; if <img src="collapse.gif" /> is clicked then <img src="expand.gif">;

Thank you.

Jamojo,

The two uses of the details function are now different enough to warrant two separate functions:

$(function() {
	var buttonImages = ['expand.gif','collapse.gif'];
	$("tr.detailsRow").hide();
	$detailsButtons = $(".detailsButton").click(function details() {
		var $button = $(this);
		var $tbody = $button.closest("tbody");
		var $r = $tbody.find("tr.detailsRow").toggle();
		$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('src',buttonImages[0]);
		$button.attr('src', buttonImages[$r.is(':hidden')?0:1]); 
	});
	$detailsButtons.closest("tr").find("input").click(function details() {
		var $tbody = $(this).closest("tbody");
		var $button = $tbody.find(".detailsButton");
		var $r = $tbody.find("tr.detailsRow").show();
		$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('src',buttonImages[0]);
		$button.attr('src',buttonImages[1]);
	});
});

This should work, though it's probably not as efficient as it could be.

Airshow

commented: Nice piece of code :) +8

Nice! Perhaps add var on line 4?

Whoops! Definitely.

Add var on line 4.

Thanks Twiss.

Airshow

You could also change $r.is(':hidden')?0:1 to !$r.is(':hidden') . Not sure if that would make it faster, but shorter at least :)

Could do. I decided to keep the 0 and 1 explicit for better readability. (Debatable point though).

A

Yes, that's the con, indeed. Well, nice effort :)

There's something else I forgot in the first click function:

return false;

Though for some reason it doesn't appear to matter (at least in Opera).

Anybody?

A

Does it make a difference in chrome? Because chrome normally jumps to ths top without it.

Twiss,

I don't have Chrome (at least not on this netbook). It's ok in IE9.

Maybe return false is unnecessary because there's no href at all.

Thinking about it, browsers should make no assumption about href (when it's not specified) because <a> can (since very early days of HTML) be used as a true anchor, as in <a name="section1">Section 1</a> . Clicking on "Section 1" does not cause a hyperlink action.

I think my code has inadvertently exploited this feature.

Airshow

Yes. But if you specify href=# it's still necessary - and I think that is a good indication of javascript onclick, but well. Never mind.

Thanks for the replies.

This works for me as far as I'm concern. Just new in JQUERY.

Still working on the mouse over of the table rows. Maybe anyone can give me some advise.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<style type="text/css">
	.detail_header_active{
		background-color:#EBE9E9;
	}
	.detail_header_inactive{
		background-color:#FFFFFF;
	}
	.detailsRow {
		background-color:#E0E0E0;
	}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
		var buttonImages = ['images/img_row_unselect_over.gif','images/img_row_select_over.gif'];
		var buttonAlt = ['Expand','Collapse'];
		var trHeaderBgColor = ['detail_header_inactive','detail_header_active'];
		$("tr.detailsRow").hide();
		var $detailsButtons = $(".detailsButton").click(function details() {
			var $button = $(this);
			var $tbody = $button.closest("tbody");
			var $r = $tbody.find("tr.detailsRow").toggle();
			$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('src',buttonImages[0]);
			$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('alt',buttonAlt[0]);
			$button.attr('src', buttonImages[$r.is(':hidden')?0:1]); 
			$button.attr('alt', buttonAlt[$r.is(':hidden')?0:1]); 
			//
			var $button1 = $tbody.find("tr.detailHeader");
			var $r1 = $tbody.find("tr.detailHeader").show();
			$("tr.detailHeader").not($r1).addClass(trHeaderBgColor[0]).removeClass(trHeaderBgColor[1]).find("tr.detailHeader").addClass(trHeaderBgColor[1]).removeClass(trHeaderBgColor[0]);
			$button1.addClass(trHeaderBgColor[1]).removeClass(trHeaderBgColor[0]);
		});
		$detailsButtons.closest("tr").find("input").click(function details() {
			var $tbody = $(this).closest("tbody");
			var $button = $tbody.find(".detailsButton");
			var $r = $tbody.find("tr.detailsRow").show();
			$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('src',buttonImages[0]);
			$("tr.detailsRow").not($r).hide().closest("tbody").find(".detailsButton").attr('alt',buttonAlt[0]);
			$button.attr('src',buttonImages[1]);
			$button.attr('alt',buttonAlt[1]);
			var $tbody1 =  $(this).closest("tbody");
			var $button1 = $tbody1.find("tr.detailHeader");
			var $r1 = $tbody1.find("tr.detailHeader").show();
				//$("tr.detailHeader").not($r1).css('background-color',trHeaderBgColor[0]).find("tr.detailHeader").css('background-color',trHeaderBgColor[1]);
			//alert(trHeaderBgColor[0]);
			$("tr.detailHeader").not($r1).addClass(trHeaderBgColor[0]).removeClass(trHeaderBgColor[1]).find("tr.detailHeader").addClass(trHeaderBgColor[1]).removeClass(trHeaderBgColor[0]);
			//$button1.css('background-color',trHeaderBgColor[1]); 
			$button1.addClass(trHeaderBgColor[1]).removeClass(trHeaderBgColor[0]);
		});
});
</script>
</head> 
<body>
	<table border="1" cellpadding="10">  
		<tr>    
			<th>&nbsp;</th>    
			<th>Column 1</th>    
			<th>Column 2</th>    
			<th>Column 3</th>    
			<th>Column 4</th>  
		</tr>  
		<tbody>  
		<tr class="detailHeader">    
			<td align="center"><a href="javascript:void(0);"><img src="images/img_row_unselect_over.gif" alt="Expand" border="0" class="detailsButton"/></a></td>
			<td><input type="text" name="textfield" /></td>    
			<td><input type="text" name="textfield2" /></td>    
			<td><input type="text" name="textfield3" /></td>    
			<td><input type="text" name="textfield4" /></td>  
		</tr>  
		<tr class="detailsRow">    
			<td colspan="5">Row 1 details </td>  
		</tr>  
		</tbody>  
		<tbody>  
		<tr class="detailHeader">    
		<td><a href="javascript:void(0);"><img src="images/img_row_unselect_over.gif" alt="Expand" border="0" class="detailsButton"/></a></td>
		<td><input type="text" name="textfield5" /></td>    
		<td><input type="text" name="textfield6" /></td>    
		<td><input type="text" name="textfield7" /></td>    
		<td><input type="text" name="textfield8" /></td>  
		</tr>  
		<tr class="detailsRow">    
		<td colspan="5">Row 2 details </td>  
		</tr>  
		</tbody>  
		<tbody>  
			<tr class="detailHeader">    
				<td><a href="javascript:void(0);"><img src="images/img_row_unselect_over.gif" alt="Expand" border="0" class="detailsButton"/></a></td>
				<td><input type="text" name="textfield9" /></td>    
				<td><input type="text" name="textfield10" /></td>    
				<td><input type="text" name="textfield11" /></td>    
				<td><input type="text" name="textfield12" /></td>  
			</tr>  
			<tr class="detailsRow">    
				<td colspan="5">Row 3 details </td>  
			</tr>  
		</tbody>
		</table>
	</body>
</html>

Jamojo,

You're nearly there.

For mouseover effect, it's simple; you can just use tr.xxxx:hover in the stylesheet.

If you also want the different background color to "latch in" for the selected rows (header and its details), then you might want something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<style type="text/css">
	tr.detailHeader {
		background-color:#FFFFFF;
	}
	tr.detailHeader:hover,
	tr.detailHeaderActive {
		background-color:#EBE9E9;
	}
	tr.detailsRow {
		background-color:#E0E0E0;
	}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
	var buttonImages = ['images/img_row_unselect_over.gif','images/img_row_select_over.gif'];
	var buttonAlt = ['Expand','Collapse'];
	var active = 'detailHeaderActive';
	var $headerRows = $("tr.detailHeader");
	var $detailsRows = $("tr.detailsRow").hide();
	var $detailsButtons = $(".detailsButton").click(function details() {
		var $button = $(this);
		var $tbody = $button.closest("tbody");
		var $r = $tbody.find("tr.detailsRow").toggle();
		$detailsRows.not($r).hide().closest("tbody").find(".detailsButton").attr({
			src: buttonImages[0],
			title: buttonAlt[0]
		});
		var i  = $r.is(':hidden') ? 0 : 1;
		var fn = $r.is(':hidden') ? 'removeClass' : 'addClass';
		$button.attr({
			src: buttonImages[i],
			title: buttonAlt[i]
		});
		var $r1 = $tbody.find("tr.detailHeader")[fn](active);
		$headerRows.not($r1).removeClass(active);
		return false;
	});
	$detailsButtons.closest("tr").find("input").click(function details() {
		var $tbody = $(this).closest("tbody");
		var $button = $tbody.find(".detailsButton");
		var $r = $tbody.find("tr.detailsRow").show();
		$detailsRows.not($r).hide().closest("tbody").find(".detailsButton").attr({
			src: buttonImages[0],
			title: buttonAlt[0]
		});
		$button.attr({
			src: buttonImages[1],
			title: buttonAlt[1]
		});
		var $r1 = $tbody.find("tr.detailHeader").addClass(active);
		$headerRows.not($r1).removeClass(active);
	});
});
</script>

</head>

<body>
<table border="1" cellpadding="10">
  <tr>
    <th>&nbsp;</th>
    <th>Column 1</th>
    <th>Column 2</th>
    <th>Column 3</th>
    <th>Column 4</th>
  </tr>
  <tbody>
  <tr class="detailHeader">
    <td><a class="detailsButton"><img src="expand.gif" width="72" height="20" /></a></td>
    <td><input type="text" name="textfield" /></td>
    <td><input type="text" name="textfield2" /></td>
    <td><input type="text" name="textfield3" /></td>
    <td><input type="text" name="textfield4" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 1 details </td>
  </tr>
  </tbody>
  <tbody>
  <tr class="detailHeader">
    <td><a class="detailsButton"><img src="expand.gif" width="72" height="20" /></a></td>
    <td><input type="text" name="textfield5" /></td>
    <td><input type="text" name="textfield6" /></td>
    <td><input type="text" name="textfield7" /></td>
    <td><input type="text" name="textfield8" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 2 details </td>
  </tr>
  </tbody>
  <tbody>
  <tr class="detailHeader">
    <td><a class="detailsButton"><img src="expand.gif" width="72" height="20" /></a></td>
    <td><input type="text" name="textfield9" /></td>
    <td><input type="text" name="textfield10" /></td>
    <td><input type="text" name="textfield11" /></td>
    <td><input type="text" name="textfield12" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 3 details </td>
  </tr>
  </tbody>
  <tbody>
  <tr class="detailHeader">
    <td><a class="detailsButton"><img src="expand.gif" width="72" height="20" /></a></td>
    <td><input type="text" name="textfield13" /></td>
    <td><input type="text" name="textfield14" /></td>
    <td><input type="text" name="textfield15" /></td>
    <td><input type="text" name="textfield16" /></td>
  </tr>
  <tr class="detailsRow">
    <td colspan="5">Row 4 details </td>
  </tr>
  </tbody>
</table>
</body>
</html>

You will see that jquery allows multiple attrs to be set using a name:value "map", thus avoiding the need to repeat the selector (which would be inefficient).

Also, by exploiting CSS's cascading rules, we can control background color of the header rows by adding/removing a single class, detailHeaderActive , as opposed to two classes working in antiphase.

Airshow

Tested in Opera 11.50 and IE9.

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.