I am having an issue with my JavaScript code. I was able to successfully implement the collapse and expand functionality for individual sub-items, but when I try to use the header as a master control to collapse and expand all sub-items at once, it doesn’t work. Additionally, when I click the header, it shows extra sub-items that are not related to the table.
Problem 1 : I found that the tbody selector is not working.
const subSections = targetSection.querySelectorAll(‘tbody’);
Problem 2 : When clicking the second time,extra sub-items appear.The sub-item order is also incorrect.
targetSection.style.display = ‘table-row-group’;
Before :image before clicked.
After : Image after clicked.
Expected Result:
I want the 2.0 Variation Order to act as the master control for all child items, such as sub-items like V0-002, allowing them to collapse and expand.
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Variation Orders</title>
<link rel="stylesheet" href="path/to/your/css/file.css"> <!-- Link to your CSS file -->
<style>
/* Basic styling for clarity */
.table { width: 100%; border-collapse: collapse; }
.table th, .table td { border: 1px solid #ddd; padding: 8px; }
.bg-light { background-color: #f8f9fa; }
.bg-white { background-color: #ffffff; }
.fw-bold { font-weight: bold; }
.text-end { text-align: right; }
.text-click { cursor: pointer; }
.text-danger { color: red; }
.expandable-header { cursor: pointer; }
.toggle-icon, .toggle-all-icon { cursor: pointer; }
.arrow { display: inline-block; width: 10px; height: 10px; transform: rotate(0deg); transition: transform 0.3s ease; }
.down { transform: rotate(90deg); }
.up { transform: rotate(0deg); }
</style>
</head>
<body>
<table class="table table-striped">
<thead>
<tr class="bg-light expandable-header" data-target="#variationOrdersSection">
<td colspan="10" style="font-weight: bold; text-align: left; cursor: pointer;">
<span class="toggle-all-icon"><i class="arrow down"></i></span> 2.0 Variation Order
</td>
</tr>
</thead>
<tbody id="variationOrdersSection" style="display:none;">
<!-- Example rendering for variation orders -->
<tr class="bg-white fw-bold"
data-total-claim="5000"
data-to-date-percent="75"
data-to-date="3750"
data-current-percent="25"
data-current="1250"
data-previous-percent="50"
data-previous="2500"
data-name="VO-001"
data-variation-id="1"
data-target="#variation-1">
<td>
<span class="toggle-icon" style="font-weight: bold; text-align: left; cursor: pointer;"
data-target="#variation-1">
<i class="arrow down"></i>
</span>
</td>
<td class="text-capitalize ps-3">VO-001</td>
<td></td>
<td class="text-end">$5,000.00</td>
<td class="text-end">75%</td>
<td class="text-end">$3,750.00</td>
<td class="text-end">50%</td>
<td class="text-end">$2,500.00</td>
<td class="text-end">25%</td>
<td class="text-end">$1,250.00</td>
</tr>
<tbody id="variation-1" style="display:none;">
<!-- Example parent section for the variation -->
<tr class="client-progress-claim-sub-section fw-bold"
parent-section-id="101"
sub-section-name="Electrical"
variation-order-id="1">
<td></td>
<td>A</td>
<td><span>Electrical</span></td>
<td class="text-end sub-section-amount">$2,000.00</td>
<td class="text-end">40%</td>
<td class="text-end">$800.00</td>
<td class="text-end">30%</td>
<td class="text-end">$600.00</td>
<td class="text-end">10%</td>
<td class="text-end">$200.00</td>
</tr>
<!-- Sub-sections under the parent section -->
<tr class="client-progress-claim-sub-section"
parent-section-id="101"
sub-section-id="201"
sub-section-name="Wiring"
variation-order-id="1">
<td></td>
<td>A.1</td>
<td><a href="/ProgressClaim/item/1/variationorder/1/lineitems/101/201">Wiring</a></td>
<td class="text-end sub-section-amount">$1,000.00</td>
<td class="text-end">50%</td>
<td class="text-end">$500.00</td>
<td class="text-end">30%</td>
<td class="text-end">$300.00</td>
<td class="text-end">20%</td>
<td class="text-end">$200.00</td>
</tr>
<!-- Subtotal for the parent section -->
<tr class="client-progress-claim-section-sub-total bg-light" parent-section-id="101">
<td></td>
<td colspan="2" align="right"><b>Section A - Sub-total</b></td>
<td class="text-end fw-bold">$2,000.00</td>
<td class="text-end fw-bold">40%</td>
<td class="text-end fw-bold">$800.00</td>
<td class="text-end fw-bold">30%</td>
<td class="text-end fw-bold">$600.00</td>
<td class="text-end fw-bold">10%</td>
<td class="text-end fw-bold">$200.00</td>
</tr>
</tbody>
</tbody>
</table>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Handle the main Variation Order header toggle
const mainToggles = document.querySelectorAll('.expandable-header');
mainToggles.forEach(function (toggle) {
toggle.addEventListener('click', function () {
// Get the target tbody to toggle
const targetId = toggle.getAttribute('data-target');
const targetSection = document.querySelector(targetId);
// If the section doesn't exist, do nothing
if (!targetSection) return;
// Find the arrow inside the toggle
const arrowIcon = toggle.querySelector('.arrow');
// Check if the target section is currently visible or not
const isHidden = targetSection.style.display === 'none' || targetSection.style.display === '';
// Toggle the main section visibility
if (isHidden) {
targetSection.style.display = 'table-row-group'; // Show the main section
arrowIcon.classList.remove('down');
arrowIcon.classList.add('up');
// Expand all sub-items (assumes sub-items are tbody elements within targetSection)
const subSections = targetSection.querySelectorAll('tbody');
console.log("subSections:", subSections);
subSections.forEach(function (subSection) {
subSection.style.display = 'table-row-group'; // Show all sub-items
});
// Change all sub-item arrows to 'up'
const subArrows = targetSection.querySelectorAll('.toggle-icon .arrow');
subArrows.forEach(function (arrow) {
arrow.classList.remove('down');
arrow.classList.add('up');
});
} else {
targetSection.style.display = 'none'; // Hide the main section
arrowIcon.classList.remove('up');
arrowIcon.classList.add('down');
// Collapse all sub-items
const subSections = targetSection.querySelectorAll('tbody');
subSections.forEach(function (subSection) {
subSection.style.display = 'none'; // Hide all sub-items
});
// Change all sub-item arrows to 'down'
const subArrows = targetSection.querySelectorAll('.toggle-icon .arrow');
subArrows.forEach(function (arrow) {
arrow.classList.remove('up');
arrow.classList.add('down');
});
}
});
});
// Handle sub-item toggles (for each sub-item in the variation orders)
const subItemToggles = document.querySelectorAll('.toggle-icon');
subItemToggles.forEach(function (icon) {
icon.addEventListener('click', function (e) {
// Prevent the event from affecting the main header toggle
e.stopPropagation();
// Get the target tbody for the sub-items
const targetId = icon.getAttribute('data-target');
const targetSection = document.querySelector(targetId);
// If the section doesn't exist, do nothing
if (!targetSection) return;
// Find the arrow inside the icon
const arrowIcon = icon.querySelector('.arrow');
// Check if the target section is currently visible or not
const isHidden = targetSection.style.display === 'none' || targetSection.style.display === '';
// Use 'table-row-group' to show the sub-items properly
if (isHidden) {
targetSection.style.display = 'table-row-group'; // Show the sub-items
arrowIcon.classList.remove('down');
arrowIcon.classList.add('up');
} else {
targetSection.style.display = 'none'; // Hide the sub-items
arrowIcon.classList.remove('up');
arrowIcon.classList.add('down');
}
});
});
});
</script>
</body>
</html>
JavaScript
<script> document.addEventListener('DOMContentLoaded', function () {
// Handle the main Variation Order header toggle
const mainToggles = document.querySelectorAll('.expandable-header');
mainToggles.forEach(function (toggle) {
toggle.addEventListener('click', function () {
// Get the target tbody to toggle
const targetId = toggle.getAttribute('data-target');
const targetSection = document.querySelector(targetId);
// If the section doesn't exist, do nothing
if (!targetSection) return;
// Find the arrow inside the toggle
const arrowIcon = toggle.querySelector('.arrow');
// Check if the target section is currently visible or not
const isHidden = targetSection.style.display === 'none' || targetSection.style.display === '';
// Toggle the main section visibility
if (isHidden) {
targetSection.style.display = 'table-row-group'; // Show the main section
arrowIcon.classList.remove('down');
arrowIcon.classList.add('up');
// Expand all sub-items (assumes sub-items are tbody elements within targetSection)
const subSections = targetSection.querySelectorAll('tbody');
console.log("subSections:", subSections);
subSections.forEach(function (subSection) {
subSection.style.display = 'table-row-group'; // Show all sub-items
});
// Change all sub-item arrows to 'up'
const subArrows = targetSection.querySelectorAll('.toggle-icon .arrow');
subArrows.forEach(function (arrow) {
arrow.classList.remove('down');
arrow.classList.add('up');
});
} else {
targetSection.style.display = 'none'; // Hide the main section
arrowIcon.classList.remove('up');
arrowIcon.classList.add('down');
// Collapse all sub-items
const subSections = targetSection.querySelectorAll('tbody');
subSections.forEach(function (subSection) {
subSection.style.display = 'none'; // Hide all sub-items
});
// Change all sub-item arrows to 'down'
const subArrows = targetSection.querySelectorAll('.toggle-icon .arrow');
subArrows.forEach(function (arrow) {
arrow.classList.remove('up');
arrow.classList.add('down');
});
}
});
});
// Handle sub-item toggles (for each sub-item in the variation orders)
const subItemToggles = document.querySelectorAll('.toggle-icon');
subItemToggles.forEach(function (icon) {
icon.addEventListener('click', function (e) {
// Prevent the event from affecting the main header toggle
e.stopPropagation();
// Get the target tbody for the sub-items
const targetId = icon.getAttribute('data-target');
const targetSection = document.querySelector(targetId);
// If the section doesn't exist, do nothing
if (!targetSection) return;
// Find the arrow inside the icon
const arrowIcon = icon.querySelector('.arrow');
// Check if the target section is currently visible or not
const isHidden = targetSection.style.display === 'none' || targetSection.style.display === '';
// Use 'table-row-group' to show the sub-items properly
if (isHidden) {
targetSection.style.display = 'table-row-group'; // Show the sub-items
arrowIcon.classList.remove('down');
arrowIcon.classList.add('up');
} else {
targetSection.style.display = 'none'; // Hide the sub-items
arrowIcon.classList.remove('up');
arrowIcon.classList.add('down');
}
});
});
});
</script>