Search code examples
javahtmlcssbootstrap-4thymeleaf

How to use th:classapend if a form error on another field exists?


Using Thymeleaf, I want to append a CSS class to a div in a row if a specific error div (reserved for a form input error) is not visible.

I'm using Bootstrap 4, and it's grid system. I tried some column offset to bring the corresponding error divs into their right position. You may think of a map with one input field for the key and one for the value. The input fields for single map entries (key-value pairs) appear in a row, and the divs for the error messages o a row below these input fields. I have a few different cases: * error in the key input field (e.g., duplicate, or empty key) plus error in the value input field (here I use just two col-6 Bootstrap classes) - no trouble with this case, here I only use columns with the same width as the input fields * error in only the key input field - also no problem, as all is left aligned * error in just the value input field - here, I want to use a column offset CSS class, which will depend on the fact that there is no input error on the key

<form ...>
...
  <div th:each="item, iter: ${viewModel.map}">

    <div class="input-group control-group mt-1">
      <input th:field="${viewModel.map[__${iter.index}__].key}"
        th:errorClass="is-invalid"
        class="form-control">
      <input th:field="${viewModel.map[__${iter.index}__].value}"
        th:errorClass="is-invalid"
        class="form-control">
    </div>

    <div class="row invalid-feedback">
      <div class="col-6"
        th:errors="${viewModel.map[__${iter.index}__].key}"></div>
      <div class="col-6"
        th:errors="${viewModel.map[__${iter.index}__].value}"></div>
      <!-- I've been trying something like the following for the value
        th:classappend="${viewModel.map[__${iter.index}__].key == null ? offset-sm-6 : ''}"
      -->
    </div>
  </div>
...
</form>

The view should look something like the following in case the key does not have any errors, but the value field has some error

| input key      | input value      |
|                | error message    |

Solution

  • After doing some further research, I was able to solve this with #fields.hasErrors on the left column property part (see the line with th:classappend:

    <form ...>
    ...
      <div th:each="item, iter: ${viewModel.map}">
    
        <div class="input-group control-group mt-1">
          <input th:field="${viewModel.map[__${iter.index}__].key}"
            th:errorClass="is-invalid"
            class="form-control">
          <input th:field="${viewModel.map[__${iter.index}__].value}"
            th:errorClass="is-invalid"
            class="form-control">
        </div>
    
        <div class="row invalid-feedback">
          <div class="col-6"
            th:errors="${viewModel.map[__${iter.index}__].key}"></div>
          <div class="col-6"
            th:classappend="${#fields.hasErrors('${viewModel.map[__${iter.index}__].key}') ? '' : 'offset-sm-6'}"
            th:errors="${viewModel.map[__${iter.index}__].value}"></div>
        </div>
      </div>
    ...
    </form>