Reputation: 142
I'm attempting to make a table that has header rows that can be collapsed and expanded by using jQuery. Here is the entirety of my code thus far:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<link href="styles.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$(document).ready(function() {
$("tr#cat1.header").click(function () {
$("tr#cat1.child").each(function() {
$(this).slideToggle("fast");
});
});
});
</script>
</head>
<body>
<table>
<tr id="cat1" class="header">
<td>Cat1</td>
<td>Row</td>
</tr>
<tr id="cat1" class="child">
<td>data1</td>
<td>data2</td>
</tr>
<tr id="cat1" class="child">
<td>data3</td>
<td>data4</td>
</tr>
<tr id="cat2" class="header">
<td>Cat1</td>
<td>Row</td>
</tr>
<tr id="cat2" class="child">
<td>data1</td>
<td>data2</td>
</tr>
</table>
</body>
</html>
If I am correct, the jQuery part in English reads like: "When a row that has an ID of 'cat1' and a class of 'header' is clicked, find all rows that have an id of 'cat1' and a class of 'child', and for each one, slideToggle."
Yet when I run it and click on a header row, nothing happens. Any insight?
EDIT: Added a second category to the HTML table. Sorry, I should have been more specific. I want to be able to click on a header row for a particular category, and have only those child rows collapse, not all child rows on the page. In such a manner the table behaves like an "accordian", and the rows are grouped together by category.
Upvotes: 5
Views: 16465
Reputation: 12793
This is an expansion of @Rory's answer to handle multiple levels of hierarchy, also I prefer fadeToggle
to slideToggle
as (at least in FF v24) when you have hundreds of rows in your table then the slideToggle
does nothing for a second and then all the rows suddenly disappear - which makes you wonder if you've actually clicked the row. fadeToggle
instantly begins to fade the rows so you know something's happening.
Instead of the child
class I use the id
of the direct parent, then you can recursively work through each branch. Also there is a 'collapsed' class that I use to fix the bug of collapsing a parent row when there is a child row that is already collapsed.
Please see the JSFiddle of the below code:
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$(document).ready(function() {
$('tr.header').click(function () {
toggleRowChildren($(this), 'header');
});
function toggleRowChildren(parentRowElement, parentClass) {
var childClass = parentRowElement.attr('id');
$('tr.'+childClass, parentRowElement.parent()).fadeToggle('fast');
$('tr.'+childClass).each(function(){
if ($(this).hasClass(parentClass) && !$(this).hasClass('collapsed')) {
toggleRowChildren($(this), parentClass);
}
});
parentRowElement.toggleClass('collapsed');
}
});
</script>
</head>
<body>
<table class="table table-hover table-bordered">
<tr id="cat1" class="header">
<th>Cat1</th>
<th>Row</th>
</tr>
<tr class="cat1">
<td>data1</td>
<td>data2</td>
</tr>
<tr id="cat1a" class="header cat1">
<th>Cat1a</th>
<th>Row</th>
</tr>
<tr class="cat1a">
<td>data1</td>
<td>data2</td>
</tr>
<tr class="cat1a">
<td>data3</td>
<td>data4</td>
</tr>
<tr id="cat2" class="header">
<th>Cat2</th>
<th>Row</th>
</tr>
<tr class="cat2">
<td>data1</td>
<td>data2</td>
</tr>
</table>
</body>
</html>
Upvotes: 0
Reputation: 63435
Firstly, you shouldn't have duplicate IDs for the rows. IDs should be unique for each element on the page.
Also, you shouldn't have to use each
, as jQuery will automatically apply the slideToggle
function to each element matched by the selector. I would suggest dropping the IDs and using the class names instead:
$("tr.header").click(function () {
$("tr.child").slideToggle("fast");
});
If you want to make sure only certain tables can perform this toggle functionality, put a class on the table and update your selectors:
<table class="collapsible">
<tr>
<td>Cat1</td>
<td>Row</td>
</tr>
<tr>
<td>Collapsible</td>
<td>Row</td>
---
$(".collapsible tr:first").click(function () {
$(this).nextAll().slideToggle("fast");
});
Rory's answer is correct, I am simply expanding upon it. If you use multiple tables, you can remove the CSS classes from the <tr>
s on the rows and simplify the tables down to:
<table class="collapsible">
<tr>
<td>Cat1</td>
<td>Cat1</td>
</tr>
<tr>
<td>Collapsible</td>
<td>Row</td>
</tr>
</table>
<table class="collapsible">
<tr>
<td>Cat2</td>
<td>Cat2</td>
</tr>
<tr>
<td>Collapsible</td>
<td>Row</td>
</tr>
</table>
and the jQuery down to:
$(".collapsible tr:first").click(function () {
$(this).nextAll().slideToggle("fast");
});
Upvotes: 7
Reputation: 2742
This will cause the click to only affect the rows in the table containing the header you clicked on, which means you can change it to work with a css class instead of duplicating the id.
$("tr#cat1.header").click(function () {
$("tr#cat1.child", $(this).parent()).slideToggle("fast");
});
Basically this
is the header that is clicked, we wrap that in a jQuery object and call parent()
(which returns the table), and then specify it as the context for the new query.
Your page now looks something like this:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<link href="styles.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$(document).ready(function() {
$("tr.header").click(function () {
$("tr.child", $(this).parent()).slideToggle("fast");
});
});
</script>
</head>
<body>
<table>
<tr class="header">
<td>Cat1</td>
<td>Row</td>
</tr>
<tr class="child">
<td>data1</td>
<td>data2</td>
</tr>
<tr class="child">
<td>data3</td>
<td>data4</td>
</tr>
</table>
<table>
<tr class="header">
<td>Cat1</td>
<td>Row</td>
</tr>
<tr class="child">
<td>data1</td>
<td>data2</td>
</tr>
<tr class="child">
<td>data3</td>
<td>data4</td>
</tr>
</table>
</body>
</html>
Upvotes: 8
Reputation: 11576
Shouldn't it be more like this? I mean, this is normally the whole document.
$("tr#cat1.header").click(function () {
$("tr#cat1.child").slideToggle("fast");
});
Upvotes: -1