Thymeleaf多选编辑时的选中状态

16

我完全改变了这个问题,其中部分已在此处得到了Avnish的大力帮助!Tom将我引导到了正确的方向,所以谢谢Tom!

我的问题是我不知道如何告诉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,...]这样的id字符串,而是类似于[Part@ 43b45j,Part@ we43y7,...]的Part实例。

更新:我刚刚注意到,如果只选择一个零件,则可以正常工作:

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

如果选择了多个部件,则无法正常工作。

6个回答

18
在Thymeleaf论坛上讨论后,我在https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple上实现了一个完整的工作示例。 我认为你最终代码唯一的问题是必须使用双大括号语法来调用conversionService:
th:value="${{part}}"

实现适当的equals()和hashcode()方法对于确保Part类的正确比较也非常重要。

我希望我的示例能帮助将来遇到类似问题的其他用户。


4
在你的Part类中实现适当的equals()和hashcode()方法非常重要,以确保正确的比较。 - Blejzer

10
通常情况下,在使用th:field时,无需使用th:selected。即使它是multiple,Thymeleaf也会自动检查每个<option>的值。
问题在于值。您正在迭代parts,但每个选项的值为part.id。 因此,您正在将部件实例与部件ID进行比较(据我所见)。
然而,Thymeleaf还考虑了PropertyEditor的实例(它重用org.springframework.web.servlet.tags.form.SelectedValueComparator)。
当比较对象和选项值时,将使用此实例。它将把对象转换为其文本值(即其ID),并将其与值进行比较。
<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。在Spring中,现在更倾向于注册在conversionService中的Converter实例。


谢谢你提供这个很好的答案。我已经进行了调整并实施了您的建议,但它仍然无法正常工作。我没有收到任何错误或其他提示...您能告诉我在哪里查找转换器的示例或文档吗?我只找到了Spring API...这样我就可以理解这个自定义编辑器应该如何工作... - Blejzer
我终于实现了转换器。花了一些时间,但它可以工作了。谢谢你。我尝试使用自定义属性编辑器,也可以正常工作。只是我无法让thymeleaf工作。我将编辑我的问题,以便您和其他人可以看到... - Blejzer

2
这是我的解答:

这适用于我:

兽医有许多专业。

控制器:

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

我必须在SpecialtyRepository中定义findOne(@Param("id") Integer id) throws DataAccessException;,否则会抛出以下异常:“java.lang.IllegalStateException: Repository没有声明find-one-method!”

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

2
嘿,非常感谢!你救了我一命!这对我也起作用:循环 th:each="author : ${authors}" 并选择 th:selected="${task.userList.contains(author)}"。 - Orkhan Hasanli

1

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>

我的 DTO 包含:
private List<String> influenceIds;

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

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

    </option>
</select>

简单的选择示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接