4
\$\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.

Anyone 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]

\$\endgroup\$
  • \$\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.