dropdown lists with Thymeleaf and SpringBoot
You have forgot indicate the field from where it has to take the selected value:
Example: I supousse the User class has an attribute for institution.
<div class="form-group">
<label class="col-md-3 control-label">Institution</label>
<div class="col-md-5">
<div th:if="${institutionList != null and not #lists.isEmpty(institutionList)}">
<select th:field="*{institution}">
<option th:each="dropDownItem : ${institutionList}"
th:value="${dropDownItem.name}"
th:text="${dropDownItem.name}" />
</select>
</div>
<div th:if="${institutionList == null or lists.isEmpty(institutionList)}">
<div>"No Institutions were found, please create some first"</div>
</div>
</div>
More info: http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dropdownlist-selectors
EDIT: You need to indicate to your app how convert a Id of Insitution returned inside form (String type) to a Institution entity. For that you have to use a Converter.
First change the value of option to institutionId:
<div class="form-group">
<label class="col-md-3 control-label">Institution</label>
<div class="col-md-5">
<div th:if="${institutionList != null and not #lists.isEmpty(institutionList)}">
<select th:field="*{institution}">
<option th:each="dropDownItem : ${institutionList}"
th:value="${dropDownItem.institutionId}"
th:text="${dropDownItem.name}" />
</select>
</div>
<div th:if="${institutionList == null or lists.isEmpty(institutionList)}">
<div>"No Institutions were found, please create some first"</div>
</div>
</div>
You have to create a class that implements the Converter interface.
@Component
public class StringToInstitution implements Converter<String, Institution> {
@Autowired
private InstitutionRepository repository; //Or the class that implments the repository.
@Override
public Institution convert(String arg0) {
Long id = new Long(arg0);
return repository.findOne(id);
}
}
sonoerin
Updated on July 14, 2022Comments
-
sonoerin almost 2 years
I have a Spring Boot 1.3 app that uses Thymeleaf on the HTML. I have page of users and when I edit them, I would like the user institution selected from a list. I have the window showing everything properly, but when I select the institution, the controller does not show the selected value.
Here is my HTML:
<div class="form-group"> <label class="col-md-3 control-label">Institution</label> <div class="col-md-5"> <div th:if="${institutionList != null and not #lists.isEmpty(institutionList)}"> <select> <option th:each="dropDownItem : ${institutionList}" th:value="${dropDownItem.name}" th:text="${dropDownItem.name}" /> </select> </div> <div th:if="${institutionList == null or lists.isEmpty(institutionList)}"> <div>"No Institutions were found, please create some first"</div> </div> </div> </div>
And here is my controller
@Controller @PreAuthorize("hasRole('Admin')") @RequestMapping("/admin") public class AdminController { @Transactional @PreAuthorize("hasRole('ADMIN')") @RequestMapping(value = "/addUser", method = RequestMethod.POST) public String checkPersonInfo(@ModelAttribute User user, Model model, Authentication authentication) { // user does not have the selected institution set customUserDetailsService.createNewUser(user); updateModelWithAllUsers(model); return "admin"; } private void updateModelWithAllUsers(Model model) { model.addAttribute(USERLIST, customUserDetailsService.findAllUsers()); model.addAttribute(INSTITUTION_LIST, institutionService.findAll()); model.addAttribute("user", new User()); } ... }
Here is my User:
@Entity @Table(name = "Users") public class User implements UserDetails { @Id private String username; @Column(nullable = false) private String password; private boolean enabled; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; private String companyName; private String email; @ElementCollection(fetch=FetchType.EAGER) @CollectionTable(name="Authorities", joinColumns=@JoinColumn(name="username")) @Column(name="authority") private Set<String> roles = new HashSet<String>(); @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "institutionId", nullable = false) private Institution institution; ... getters & setters }
And my Institution:
@Entity @Table(name = "Institution") public class Institution { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long institutionId; private String name; @OneToMany(mappedBy = "institution", fetch = FetchType.EAGER) @Fetch(value = FetchMode.SUBSELECT) List<User> users = new ArrayList<User>(); ... getters & setters }
When the "/addUser" gets the User object from the UI, the institution is null.
EDIT I used Sergios suggestion to use
select th:field="${user.institution}"
as well asselect th:field="*{institution}"
but that gives me an error:
org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'user' on field 'institution': rejected value [com.security.Institution@3e3945d2]; codes [typeMismatch.user.institution,typeMismatch.institution,typeMismatch.com. .security.Institution,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.institution,institution]; arguments []; default message [institution]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'com.security.Institution' for property 'institution'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.lang.Long for value 'com.security.Institution@3e3945d2'; nested exception is java.lang.NumberFormatException: For input string: "com. .security.Institution@3e3945d2"]
Not sure if I am reading this correctly, but does that mean Thymeleaf is trying to pass the Institution.name to the user.institution field?
Can anyone offer any advice on how to do this?
-
sonoerin about 8 yearsWhen I make that change, I get an error about type conversion 'org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.lang.Long for value 'com.security.Institution@27d1fda1'; nested exception is java.lang.NumberFormatException: For input string: "com.security.Institution@27d1fda1"' My User has a Institution attribute, and my drop down list is of that type - so not sure why its not setting the object
-
Sergio Garcia Alonso about 8 yearsWhen you send the form in the field institution you send the name of Insitution and in your User you have a attribute of Institution class then Spring try to recovery the entity from DB but it can't because Spring have a String and the id of Institution is Long.
-
Sergio Garcia Alonso about 8 years[Continuation] First you need return the Id value of institution: th:value="${dropDownItem.id}" (Or the name of id attribute) And in your app you need to have a Convert class from String to Institution, in this convert you can convert the String to Long and use your InstitutionRepository to obtain the Institution.
-
sonoerin about 8 yearsThank you so much, I had never heard of the Convert class. I guess I was expecting the Institution to come back as JSON or an object or something. That worked wonderfully, thank you for the explanation and time!