it-swarm.com.de

thymeleaf mehrfach beim Bearbeiten ausgewählt

Ich ändere diese Frage total, als ein Teil davon beantwortet wurde hier mit großer Hilfe von Avnish! Tom schickte mich in die richtige Richtung, also danke Tom!

Mein Problem ist, dass ich nicht weiß, wie ich Thymeleaf anweisen soll, Objektelemente bei der Bearbeitung vorzuwählen.

Lass mich dir zeigen:

looks like this

Diese Lösung funktioniert:

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

Ich habe das ausprobiert:

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

funktioniert nicht. Ich habe auch folgendes versucht:

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

hat auch nicht funktioniert. Ich habe versucht, th:field="*{parts}" aus dem Option-Tag zu entfernen, dasselbe Ergebnis ..

Wenn ich th:value in ${part} ändere, funktioniert es, aber es sendet keine Zeichenfolge von IDs wie [2,4,5,6, ...] zurück, sondern Part Instanzen wie [Part @ 43b45j, Part @ we43y7, ... ] ...

UPDATE: Ich habe gerade bemerkt, dass dies funktioniert, wenn nur ein Teil ausgewählt wird:

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

Wenn mehrere Teile ausgewählt sind, funktioniert es nicht ...

13
Blejzer

Nach einer Diskussion im Thymeleaf-Forum implementierte ich ein vollständiges Arbeitsbeispiel unter https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple

Ich denke, das einzige Problem mit Ihrem endgültigen Code ist, dass Sie die Doppelklammer-Syntax verwenden müssen, um den conversionService aufzurufen:

th:value="${{part}}"

Es ist auch wichtig, die richtigen equals () - und Hashcode () - Methoden in Ihrer Part-Klasse zu implementieren, um einen ordnungsgemäßen Vergleich zu gewährleisten.

Ich hoffe, mein Beispiel hilft anderen Benutzern mit ähnlichen Problemen in der Zukunft. 

12
user211430

Sie brauchen th:selected nicht, wenn Sie th:field normalerweise verwenden. Thymeleaf überprüft automatisch die Werte jedes <option> im <select>, auch wenn es multiple ist

Das Problem liegt im Wert. Sie überlaufen parts, aber der Wert jeder Option lautet part.id. Sie vergleichen also Instanzen eines Teils mit der ID eines Teils (soweit ich sehen kann).

Thymeleaf berücksichtigt jedoch auch Instanzen von PropertyEditor (es verwendet org.springframework.web.servlet.tags.form.SelectedValueComparator). 

Dies wird verwendet, wenn die Objekte mit den Werten der Optionen verglichen werden. Es konvertiert die Objekte in ihren Textwert (ihre ID) und vergleicht diesen mit dem Wert.

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

Eigenschaftseditor

Definieren Sie eine PropertyEditor für die Teile. Der PropertyEditor wird beim Vergleich der Werte und beim Zurückbinden der Teile an das Formular aufgerufen.

@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
        }
    }
}

Schauen Sie sich auch ConvertingPropertyEditorAdapter an. Converter-Instanzen, die in der conversionService registriert sind, werden heutzutage im Frühling mehr bevorzugt.

7
Tom Verelst

Das funktioniert für mich:

Ein Tierarzt hat viele Spezialitäten.

Regler:

@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;     
}

Ansicht (mit th: ausgewählt):

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

Ansicht (mit th: Feld):

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

Und ich muss Specialty findOne(@Param("id") Integer id) throws DataAccessException; im SpecialtyRepository definieren, sonst wird die folgende Ausnahme ausgelöst: "Java.lang.IllegalStateException: Repository hat keine find-one-Methode deklariert!"

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

So habe ich es gemacht:

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

Mein DTO enthält:

private List<String> influenceIds;
0