7
\$\begingroup\$

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>
 <h4 style="text-align: center">Please specify below</h4>
 <br>
 <form method="POST" id="postDetails" onsubmit="return interceptSubmit()">
 <table id="buyTable" class="table table-hover">
 <thead>
 <tr>
 <th>Type</th>
 <th>Brand</th>
 <th>Buy-Price</th>
 <th>Bottom</th>
 <th>Top</th>
 <th>Stop</th>
 <th>Reduce</th>
 <th>Start</th>
 </tr>
 </thead>
 <tbody>
 <tr th:each="car : ${cars}">
 <td>
 <select th:id="${car.getBrand()}" title="selectBuyOrSell" onchange="updateBuyTable(this)">>
 <option value="buy">Buy</option>
 <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"
 name="buyPrice"/></td>
 <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]

Sᴀᴍ Onᴇᴌᴀ
29.6k16 gold badges45 silver badges202 bronze badges
asked Aug 16, 2018 at 11:43
\$\endgroup\$
2
  • 2
    \$\begingroup\$ 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}". \$\endgroup\$ Commented Aug 16, 2018 at 14:30
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Nov 29, 2019 at 11:43

1 Answer 1

1
\$\begingroup\$

Your question

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 HTMLCollection 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 and other bugs.

  • document.getElementsByClassName() returns a Live HTMLCollection 1 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.

  • 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.

answered Oct 28, 2019 at 18:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.