Je change totalement cette question, car une partie de celle-ci a été résolue ici avec la grande aide de Avnish! Tom m'a envoyé dans la bonne direction, alors merci Tom!
Mon problème est que je ne sais pas comment dire à Thymeleaf de présélectionner des éléments d'objet lors de son édition.
Laisse moi te montrer:
Cette solution fonctionne:
<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>
J'ai essayé ceci:
<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>
n'a pas marché. J'ai aussi essayé ceci:
<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>
n'a pas fonctionné non plus. J'ai essayé de supprimer th:field="*{parts}"
de la balise d'option, même résultat ..
Si je remplace th:value
par ${part}
, cela fonctionne, mais il n'envoie pas de chaîne d'identifiants comme [2,4,5,6, ...], mais des instances Part
comme [Part @ 43b45j, Part @ we43y7, ... ] ...
UPDATE: Je viens de remarquer que cela fonctionne si une seule partie est sélectionnée:
<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>
Si plusieurs pièces sont sélectionnées, cela ne fonctionne pas ...
Après une discussion sur le forum Thymeleaf, j’ai mis en place un exemple de travail complet à https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple
Je pense que le seul problème avec votre code final est que vous devez utiliser la syntaxe à double crochet pour appeler le service conversionService:
th:value="${{part}}"
Il est également important d'implémenter les méthodes appropriées equals () et hashcode () dans votre classe Part pour assurer une comparaison appropriée.
J'espère que mon exemple aidera d'autres utilisateurs ayant des problèmes similaires à l'avenir.
Vous n'avez pas besoin de th:selected
lorsque vous utilisez th:field
normalement. Thymeleaf vérifiera automatiquement les valeurs de chaque <option>
dans le <select>
, même s'il s'agit de multiple
Le problème réside dans la valeur. Vous effectuez une itération sur parts
, mais la valeur de chaque option est part.id
. Ainsi, vous comparez des occurrences de partie à l'id de partie (autant que je sache).
Cependant, Thymeleaf prend également en compte les instances de PropertyEditor
(il réutilise org.springframework.web.servlet.tags.form.SelectedValueComparator
).
Ceci sera utilisé lors de la comparaison des objets aux valeurs des options. Il convertira les objets en leur valeur textuelle (leur id) et les comparera à la valeur.
<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>
Editeur de propriété
Définissez une PropertyEditor
pour les pièces. PropertyEditor sera appelé lors de la comparaison des valeurs et lors de la liaison des pièces au formulaire.
@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
}
}
}
Jetez également un coup d'oeil à ConvertingPropertyEditorAdapter
. Les instances Converter
qui sont enregistrées dans la conversionService
sont davantage préférées au printemps de nos jours.
Cela fonctionne pour moi:
Un vétérinaire a de nombreuses spécialités.
Manette:
@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;
}
Voir (en utilisant th: sélectionné):
<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>
Vue (utilisant th: champ):
<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>
Et je dois définir Specialty findOne(@Param("id") Integer id) throws DataAccessException;
dans SpecialtyRepository, sinon l'exception suivante est levée: "Java.lang.IllegalStateException: le référentiel n'a pas de méthode find-one déclarée!"
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;
}
<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>
Voici comment je l'ai fait:
<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>
Mon DTO contient:
private List<String> influenceIds;