You don't need th:selected
when using th:field
normally. Thymeleaf will automatically check the values of each <option>
in the <select>
, even if it is multiple
The problem lies in the value. You are iterating over parts
, but the value of each option is part.id
. Thus you are comparing instances of part to the id of part (as far as I can see).
However, Thymeleaf also takes into account instances of PropertyEditor
(it reuses org.springframework.web.servlet.tags.form.SelectedValueComparator
).
This will be used when comparing the objects to the values of the options. It will convert the objects to their text value (their id) and compare this to the value.
<select class="form-control" th:field="*{parts}" multiple="multiple" >
<option th:each="part : ${partsAttribute}"
<!--
Enable the SpringOptionFieldAttrProcessor .
th:field value of option must be equal to that of the select tag
-->
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name} + ${part.serial}">Part name and serial No.
</option>
</select>
Property Editor
Define a PropertyEditor
for the parts. The PropertyEditor will be called when comparing the values, and when binding the parts back to the form.
@Controller
public class PartsController {
@Autowired
private VehicleService vehicleService;
@InitBinder(value="parts")
protected void initBinder(final WebDataBinder binder) {
binder.registerCustomEditor(Part.class, new PartPropertyEditor ());
}
private static class PartPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String partId) {
final Part part = ...; // Get part based on the id
setValue(part);
}
/**
* This is called when checking if an option is selected
*/
@Override
public String getAsText() {
return ((Part)getValue()).getId(); // don't forget null checking
}
}
}
Also take a look at ConvertingPropertyEditorAdapter
. Converter
instances that are registered in the conversionService
are more preferred in Spring nowadays.