тимелеаф несколько выбран при редактировании

Я полностью меняю этот вопрос, так как на его часть был дан ответ здесь с большой помощью Авниш! Том направил меня в правильном направлении, так что спасибо, Том!

Моя проблема в том, что я не знаю, как сказать Thymeleaf предварительно выбирать элементы объекта при его редактировании.

Позволь мне показать тебе:

выглядит так

Это решение работает:

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

Я пробовал это:

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

не сработало. Я также пробовал это:

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

тоже не работал. Я попытался удалить th:field="*{parts}" из тега опции, тот же результат.

Если я изменяю th:value на ${part}, он работает, но тогда он не отправляет обратно строку идентификаторов, например [2,4,5,6,...], а Part экземпляров, таких как [Part@43b45j, Part@we43y7,... ]...

ОБНОВЛЕНИЕ: я только что заметил, что это работает, если выбрана только одна часть:

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

Если выбрано несколько частей, это не работает...


person Blejzer    schedule 07.03.2014    source источник


Ответы (5)


После обсуждения на форуме Thymeleaf я реализовал полный рабочий пример по адресу https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple

Я думаю, что единственная проблема с вашим окончательным кодом заключается в том, что вам нужно использовать синтаксис двойной скобки для вызова convertService:

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

Также важно реализовать правильные методы equals() и hashcode() в классе Part, чтобы обеспечить правильное сравнение.

Я надеюсь, что мой пример поможет другим пользователям с подобными проблемами в будущем.

person user211430    schedule 29.03.2014
comment
это обязательно: также важно реализовать правильные методы equals() и hashcode() в вашем классе Part, чтобы обеспечить правильное сравнение. - person Blejzer; 06.10.2014

Вам не нужно th:selected при обычном использовании th:field. Thymeleaf автоматически проверит значения каждого <option> в <select>, даже если это multiple

Проблема заключается в стоимости. Вы перебираете parts, но значение каждой опции равно part.id. Таким образом, вы сравниваете экземпляры части с идентификатором части (насколько я вижу).

Однако Thymeleaf также учитывает экземпляры PropertyEditor (повторно использует org.springframework.web.servlet.tags.form.SelectedValueComparator).

Это будет использоваться при сравнении объектов со значениями опций. Он преобразует объекты в их текстовое значение (их идентификатор) и сравнивает его со значением.

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

Редактор свойств

Определите PropertyEditor для деталей. Редактор свойств будет вызываться при сравнении значений и при связывании частей обратно с формой.

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

Также взгляните на ConvertingPropertyEditorAdapter. Converter экземпляры, зарегистрированные в conversionService, в настоящее время более предпочтительны в Spring.

person Tom Verelst    schedule 10.03.2014
comment
Спасибо за этот отличный ответ. Я внес коррективы и реализовал ваше предложение, и, конечно, оно все еще не работает. Я не получаю никаких ошибок или чего-то еще, просто... Можете ли вы сказать мне, где искать примеры или документацию по конвертерам, все, что я нашел, это Spring API... Просто чтобы я мог понять, как этот пользовательский редактор делает то, что он есть должен сделать... - person Blejzer; 14.03.2014
comment
Наконец-то я реализовал конвертер. Это заняло некоторое время, но это работает. Спасибо тебе за это. Я пробовал с помощью пользовательского редактора свойств, и он тоже отлично работает. Я просто не могу заставить тимелеаф работать. Я отредактирую свой вопрос, чтобы вы и другие могли видеть... - person Blejzer; 27.03.2014

Это работает для меня:

У ветеринара много специальностей.

Контроллер:

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

Просмотр (используя 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>

Просмотр (используя поле th:):

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

И я должен определить Specialty findOne(@Param("id") Integer id) throws DataAccessException; в SpecialtyRepository, иначе выдается следующее исключение: «java.lang.IllegalStateException: в репозитории не объявлен метод поиска одного!»

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;
}
person Gabriel    schedule 10.12.2016
comment
Ой, спасибо большое) Вы меня спасли! Это сработало и для меня: цикл th:each=author : ${authors} и выбор th:selected=${task.userList.contains(author)} - person Orkhan Hasanli; 27.11.2018

Вот как я это сделал:

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

Мой DTO содержит:

private List<String> influenceIds;
person Siddharth Sachdeva    schedule 28.01.2018

<select  th:field="*{groupId}" >
    <option th:each="group :${grouptype}"
            th:value="${{group.groupId}}"
            th:text="${group.Desc}">

    </option>
</select>

Пример простого выбора

person user3843726    schedule 23.07.2014