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

public String selectPost(
        @RequestParam(required = false, name = "clickboxReduce") String[] clickboxReduce,
        Model model) {
    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.

Anyone a better idea?

Here the table:

<!--- start table -->
<div class="container">
    <h4 style="text-align: center">Please specify below</h4>
    <form method="POST" id="postDetails" onsubmit="return interceptSubmit()">
        <table id="buyTable" class="table table-hover">
            <tr th:each="car : ${cars}">
                    <select th:id="${car.getBrand()}" title="selectBuyOrSell" onchange="updateBuyTable(this)">>
                        <option value="buy">Buy</option>
                        <option value="sell">Sell</option>
                    <a th:text="${car.getBrand()}"></a><input type="hidden" name="brandBuy"
                <td><input type="number" step="0.00000001" placeholder="Enter price"
                <td><input type="number" step="0.00000001" placeholder="Enter bottom"
                <td><input type="number" step="0.00000001" placeholder="Enter top"
                <td><input type="number" step="0.00000001" placeholder="Enter stop"
                    <label class="custom-control custom-checkbox">
                        <input id="clickboxReduce" name="clickboxReduce" type="checkbox" class="custom-control-input"
                               onchange="handleClickOnReduceStart(this)" checked>
                        <span class="custom-control-indicator"></span>
                    <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>
                <!--                <td><input id="clickboxReduce" type="checkbox"></td>
                                <td><input id="clickboxStart" type="checkbox"></td>-->
        <button style="float: right!important;" class="btn btn-outline-primary">Continue</button>

and the function

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

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

Output of my backend controller

clickBoxReduce [yes, no, yes]

  • \$\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\$ – RoToRa Aug 16 '18 at 14:30
  • 1
    \$\begingroup\$ I know I have looked at scenarios like this and read SO answers like this one before... \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Aug 16 '18 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.