web-dev-qa-db-fra.com

thymeleaf multiple sélectionné sur edit

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:

looks like this

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 ...

13
Blejzer

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. 

12
user211430

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.

7
Tom Verelst

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;
}
1
Gabriel
<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>
0
viniciusalvess

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;
0
Siddharth Sachdeva