Java – How to bind an object list to checkbox in thymeleaf

javaspring-mvcthymeleaf

I am having a lot of difficulty with binding checkbox inputs with a object list.Issue is when I add th:field="*{userRole}" on input field type checkbox then I am getting Bad request as response on web browser.

Here is my code:

User Model class:

public class User implements Serializable {
    private Integer id;
    private String username;
    private String password;
    private boolean enabled;
    private List<UserRole> userRole = new ArrayList<UserRole>(0);
}

UserRole Model class:

public class UserRole implements Serializable {
    @Id
    @GeneratedValue
    private Integer userRoleId;
    @ManyToMany(mappedBy = "userRole")
    private List<User> users;
    @Column(name = "role", nullable = false, length = 45)
    private String role;
}

Model Attribute:

@ModelAttribute(value = "user")
    public User userModel() {
        return new User();
}

GET Method:

@RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Map<String, Object> model) {
    List<UserRole> roles = roleService.getAllRoles();
    model.put("roles", roles);
    return "index";
}

My POST method:

@RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addUser(@ModelAttribute("user") User userModel) {

}

Index page Form :

<form role="form" action="#" th:action="@{/add}" th:object="${user}" method="post">

   <div class="form-group">
            <label for="email">User Name:</label>
            <input type="text" class="form-control" id="username"    th:field="*{username}" required autofocus>
   </div>
   <ul>
        <li th:each="item : ${roles}">
           <input type="checkbox" th:field="*{userRole}" th:value="${item}" />
           <label th:text="${item.role}">Test</label>
        </li>
    </ul>
    <input type="submit" value="Submit" />
</form>

when I click submit, browser shows as a Bad request, But without th:field="*{userRole}" I can submit the form. Any idea to resolve this issue?

—Update—

issue was Thymeleaf unable to bind object directly. So added new List of String for binding.

private List<String> userRoles = new ArrayList<>(0);

and then changed the form as @Roel mentioned.

<li th:each="item, stat : ${roles}">
    <label th:text="${stat.index}">Test</label>
    <input type="checkbox" th:field="*{userRoles[__${stat.index}__]}" th:value="${item.userRoleId}" />
    <label th:text="${item.role}">Test</label>
</li>

Thanks.

Best Answer

You are trying to add item as the value to a List. It's like trying to say ArrayList<Integer> list = 5;

What you need is to add the item to the list:

    li th:each="item, stat : ${roles}">
       <input type="checkbox" th:field="*{userRole[__${stat.index}__]}" th:value="${item}" />
       <label th:text="${item.role}">Test</label>
    </li>

I'm unsure if this will directly solve your problem as thymeleaf has issues with simply "adding" an object to a list. Thymeleaf generally works with basic types like strings and integers. But at least I pointed out where your problem lies. Try fiffling around with this a little bit. Try using this line instead, at least this will definitely work:

 <input type="checkbox" th:field="*{userRole[__${stat.index}__].role}" th:value="${item.role}" />