# Get checkbox value of unchecked checkboxes in a table

I have a table where a user can (un)check checkboxes among other features in each row.

I faced the problem that I don't receive unchecked checkboxes to my backend. This led to a bigger issue since every row should have synchronized fields of course.

For example:

• Row 1 - checked
• Row 2 - unchecked
• Row 3 - checked

My backend receives now an array like this:

clickBoxReduce [true, true]

Backend-Function like this

@PostMapping()
public String selectPost(
@RequestParam(required = false, name = "clickboxReduce") String[] clickboxReduce,
Model model) {
System.out.println("clickBoxReduce");
System.out.println(Arrays.toString(clickboxReduce));
return "fillDetails";
}


Obviously I cannot see which row exactly is unchecked.

My solution was to give each input tag a value noand yes and update this value with every checkbox click.

function handleClickOnReduceStart (element) {
if (element.value === 'yes') {
element.value = 'no'
} else if (element.value === 'no') {
element.value = 'yes'
}
}


And set all checkboxes on checked before submitting the form with the function interceptSubmit blow. With that I get all checkbox values in the correct order.

It is visible for the user that the checkboxes change again if there is a slight delay what is not so good.

Does anyone have a better idea?

Here the table:

<!--- start table -->
<div class="container">
<br>
<br>
<form method="POST" id="postDetails" onsubmit="return interceptSubmit()">
<tr>
<th>Type</th>
<th>Brand</th>
<th>Bottom</th>
<th>Top</th>
<th>Stop</th>
<th>Reduce</th>
<th>Start</th>
</tr>
<tbody>
<tr th:each="car : ${cars}"> <td> <select th:id="${car.getBrand()}" title="selectBuyOrSell" onchange="updateBuyTable(this)">>
<option value="sell">Sell</option>
</select>
</td>
<td>
<a th:text="${car.getBrand()}"></a><input type="hidden" name="brandBuy" th:value="${car.getBrand()}"/>
</td>
<td><input type="number" step="0.00000001" placeholder="Enter price"
<td><input type="number" step="0.00000001" placeholder="Enter bottom"
name="bottom"/></td>
<td><input type="number" step="0.00000001" placeholder="Enter top"
name="top"/></td>
<td><input type="number" step="0.00000001" placeholder="Enter stop"
name="stop"/></td>
<td>
<label class="custom-control custom-checkbox">
<input id="clickboxReduce" name="clickboxReduce" type="checkbox" class="custom-control-input"
value="yes"
onchange="handleClickOnReduceStart(this)" checked>
<span class="custom-control-indicator"></span>
</label>
</td>
<td>
<label class="custom-control custom-checkbox">
<input id="clickboxStart" type="checkbox" class="custom-control-input"
onchange="handleClickOnReduceStart(this)" checked>
<span class="custom-control-indicator"></span>
</label>
</td>
<!--                <td><input id="clickboxReduce" type="checkbox"></td>
<td><input id="clickboxStart" type="checkbox"></td>-->
</tr>
</tbody>
</table>
<br/>
<br/>
<button style="float: right!important;" class="btn btn-outline-primary">Continue</button>
</form>
</div>


and the function

function interceptSubmit () {
let form = document.getElementsByClassName('custom-control-input')

for (i = 0; i < form.length; i++) {
if (!form[i].checked) {
console.log('unchecked')
form[i].checked = true
}
}
return true // return false to cancel form action
}


Output of my backend controller

clickBoxReduce [yes, no, yes]

• You could just give the check boxes different names. Every row (car?) needs/should have a unique identifier, so for example th:name="\${'clickboxReduce_' + car.id}". – RoToRa Aug 16 '18 at 14:30
• Additionally, why use “yes” or “no” when true/false already have a binary representation? Just a thought. For example with JavaScript !!+”0” equals false and !!+”1” equals true. Don’t you think it would be easier to maintain and require less logic and take up less data using 0 & 1? I’m sure java has a typecast equivalent. – soulshined Nov 29 '19 at 11:43

Does anyone have a better idea?

There are multiple posts on SO like Force a checkbox to always submit, even when unchecked, which has an answer that suggests adding a hidden input with the same name as the checkbox and the opposite value (e.g. "no").

<input type="hidden" name="checkbox1" value="off">
<input type="checkbox" name="checkbox1" value="on"> My checkbox


Perhaps you should consider using different elements - e.g. radio buttons, which can be styled like more modern toggle inputs (e.g. iOS style)

## Review of existing code

Looking at interceptSubmit() I see that:

• Lines aren't terminated with semi-colons. While they are only required after a handful of statements, it could lead to errors if somehow whitespace got removed.
• The variable name form is slightly misleading - typically a form refers to a <form> element, but in this case the variable is an HTML collection of elements with a particular class name, which appears to be two checkboxes with the given HTML.

let form = document.getElementsByClassName('custom-control-input')


A more appropriate name might be customControlInputs

• form isn't re-assigned so it could be declared with const to avoid accidental re-assignment
• document.getElementsByClassName() returns a Live HTMLCollection1 so that assignment can take place outside of the function - perhaps an ideal place would be as soon as the DOM is ready
• for loop variable i is a global variable because it is not declared with var, let, etc. In general it is best to avoid global variables to avoid accidental re-assignment.
• a for...of loop could be used instead of a regular for loop if is supported by all target browsers. That would allow simplification of accessing elements of the collection.