问题
I am totally changing this question, as part of it was answered here with great help of Avnish! Tom sent me to the right direction so thank you Tom!
My problem is that I do not know how to tell Thymeleaf to preselect object elements when editing it.
Let me show you:
This solution works:
<select class="form-control" id="parts" name="parts" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:selected="${servisAttribute.parts.contains(part)}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
I have tried this:
<select class="form-control" th:field="*{parts}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
did not work. I also tried this:
<select class="form-control" th:field="*{{parts}}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
did not work either. I have tried removing th:field="*{parts}"
from the option tag, same result..
If I change th:value
to ${part}
it works, but then it does not send back string of ids like [2,4,5,6,...], but Part
instances like [Part@43b45j, Part@we43y7,...]...
UPDATE: I just noticed that this works if only one part is selected:
<select class="form-control" th:field="*{parts}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
If multiple parts are selected, it does not work...
回答1:
After discussion on the Thymeleaf forum, I implemented a full working example at https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple
I think that the only problem with your final code is that you have to use double bracket syntax to invoke the conversionService:
th:value="${{part}}"
It is also important to implement proper equals() and hashcode() methods in your Part class to assure proper comparison.
I hope my example helps other users with similar problems in the future.
回答2:
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.
回答3:
This works for me:
A vet has many specialties.
Controller:
@RequestMapping(value = "/vets/{vetId}/edit", method = RequestMethod.GET)
public ModelAndView editVet(@PathVariable("vetId") int ownerId/*, Model model*/) {
ModelAndView mav = new ModelAndView("vets/vetEdit");
mav.addObject("vet", this.vets.findById(ownerId));
mav.addObject("allSpecialties", this.specialities.findAll());
return mav;
}
View (using th:selected):
<select id="specialities" class="form-control" multiple>
<option th:each="s : ${allSpecialties}"
th:value="${s.id}"
th:text="${s.name}"
th:selected="${vet.specialties.contains(s)}">
</option>
</select>
View (using th:field):
<form th:object="${vet}" class="form-horizontal" id="add-vet-form" method="post">
<div class="form-group has-feedback">
<select th:field="*{specialties}" class="form-control" multiple>
<option th:each="s : ${allSpecialties}"
th:value="${s.id}"
th:text="${s.name}"
>
</option>
</select>
</div>
And I have to define Specialty findOne(@Param("id") Integer id) throws DataAccessException;
in the SpecialtyRepository, otherwise the following exception is thrown : "java.lang.IllegalStateException: Repository doesn't have a find-one-method declared!"
package org.springframework.samples.petclinic.vet;
import java.util.Collection;
import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
public interface SpecialtyRepository extends Repository<Specialty, Integer> {
@Transactional(readOnly = true)
Collection<Specialty> findAll() throws DataAccessException;
Specialty findOne(@Param("id") Integer id) throws DataAccessException;
}
回答4:
Here's how I did it:
<select th:field="*{influenceIds}" ID="txtCategoryName" class="m-wrap large" multiple="multiple">
<option th:each="influence : ${influences}" th:value="${influence.get('id')}" th:text="${influence.get('influence')}" ></option>
</select>
My DTO contains:
private List<String> influenceIds;
回答5:
<select id="produtos" name="selectedItens" style="width: 100%;" multiple="multiple" required="">
<option th:value="${p.id}" th:text="${p}" th:each="p : ${slideShowForm.itens}" th:selected="${#lists.contains(slideShowForm.selectedItens,p)}"></option>
</select>
回答6:
<select th:field="*{groupId}" >
<option th:each="group :${grouptype}"
th:value="${{group.groupId}}"
th:text="${group.Desc}">
</option>
</select>
Simple select example
来源:https://stackoverflow.com/questions/22246759/thymeleaf-multiple-selected-on-edit