Reputation: 526
I have a table with many expandable/collapsible rows that are hidden by labels until clicked (shown below). Input in the right-hand column of the table is meant to be edited and summed, so I have a function to set each cell to be .contentEditable
and calculate the sum total of the user-entered numbers. However, because I do not want the sum itself (in the final row of the table) to be edited, I have the following restriction to the event handler in jQuery:
document.querySelectorAll("table tr:not(:last-child) td ~ td");
While the :not(:last-child)
part gets rid of the issue of the editable final row, it creates another issue: now, the last rows of every expandable section (the "Jill" and "Jim" rows in the below example) are unable to be edited, too. Is there a way to fix this without making the absolute final row of the table ("Total") editable in the process?
To better visualize the issue, I've attached an example table that demonstrates the problem.
$(document).ready(function() {
$('.hide').hide();
$('[data-toggle="toggle"]').change(function() {
$("label[for='" + this.id + "'] span").toggle();
$(this).parents().next('.hide').toggle();
});
});
function editcell() {
let cellnum = document.querySelectorAll("table tr:not(:last-child) td ~ td");
cellnum.forEach(td => {
td.setAttribute("contentEditable", true);
td.addEventListener("change", getsum());
});
}
function getsum() {
let sum = 0;
let cellnum = document.querySelectorAll("table tr td ~ td");
let count = cellnum.length - 1;
for (i = 0; i < count; i++) {
sum += parseInt(cellnum[i].innerHTML) || 0;
}
cellnum[count].innerHTML = sum;
}
editcell();
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial;
}
[data-toggle="toggle"] {
display: none;
}
label {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody class="section">
<tr>
<td colspan="2">
<label class="label" for="class1">
<b>Class 1</b>
<span>(Click this!)</span>
</label>
<input type="checkbox" name="class1" id="class1" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Jack</td>
<td id="jack" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>John</td>
<td id="john" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jill</td>
<td id="jill" oninput="editcell()">
<span>0</span>
</td>
</tr>
</tbody>
<tbody class="section">
<tr>
<td colspan="2">
<label class="label" for="class2">
<b>Class 2</b>
<span>(Click this!)</span>
</label>
<input type="checkbox" name="class2" id="class2" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Joe</td>
<td id="joe" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jane</td>
<td id="jane" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jim</td>
<td id="jim" oninput="editcell()">
<span>0</span>
</td>
</tr>
</tbody>
<tr>
<td style="font-weight:bold; text-align: center">Total</td>
<td id="total"></td>
</tr>
</table>
Upvotes: 0
Views: 353
Reputation: 36426
You can select (to ignore) the total cell as it has a unique id:
let cellnum = document.querySelectorAll("table tr td ~ td:not(#total)");
$(document).ready(function() {
$('.hide').hide();
$('[data-toggle="toggle"]').change(function() {
$("label[for='" + this.id + "'] span").toggle();
$(this).parents().next('.hide').toggle();
});
});
function editcell() {
let cellnum = document.querySelectorAll("table tr td ~ td:not(#total)");
cellnum.forEach(td => {
td.setAttribute("contentEditable", true);
td.addEventListener("change", getsum());
});
}
function getsum() {
let sum = 0;
let cellnum = document.querySelectorAll("table tr td ~ td");
let count = cellnum.length - 1;
for (i = 0; i < count; i++) {
sum += parseInt(cellnum[i].innerHTML) || 0;
}
cellnum[count].innerHTML = sum;
}
editcell();
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial;
}
[data-toggle="toggle"] {
display: none;
}
label {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody class="section">
<tr>
<td colspan="2">
<label class="label" for="class1">
<b>Class 1</b>
<span>(Click this!)</span>
</label>
<input type="checkbox" name="class1" id="class1" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Jack</td>
<td id="jack" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>John</td>
<td id="john" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jill</td>
<td id="jill" oninput="editcell()">
<span>0</span>
</td>
</tr>
</tbody>
<tbody class="section">
<tr>
<td colspan="2">
<label class="label" for="class2">
<b>Class 2</b>
<span>(Click this!)</span>
</label>
<input type="checkbox" name="class2" id="class2" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Joe</td>
<td id="joe" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jane</td>
<td id="jane" oninput="editcell()">
<span>0</span>
</td>
</tr>
<tr>
<td>Jim</td>
<td id="jim" oninput="editcell()">
<span>0</span>
</td>
</tr>
</tbody>
<tr>
<td style="font-weight:bold; text-align: center">Total</td>
<td id="total"></td>
</tr>
</table>
Upvotes: 1