Thymeleaf - th:each 中未设置复选框的选中属性或如何正确恢复复选框列表,其中一些先前已选中

Thymeleaf - Checked attribute of checkbox is not set in th:each OR how to properly restore a list of checkboxes some of which were previously checked

在我的应用程序中,我想创建一个新的 Risk(Risk 对象的一个​​实例),并且在创建它时我想显示 5 个复选框和三个单选按钮。所选选项特定于风险对象的每个实例。

稍后我想显示所有添加的风险的列表,每个风险都有一个编辑选项按钮。我希望我的应用程序恢复特定于 selected 风险的视图(当单击 selected 风险上的编辑按钮时)-风险名称,所有复选框和单选按钮都选中为 select 以前编辑过。我希望能够再次编辑这些复选框 selections,以便所有新更改都正确反映在 MySQL.

作为 Thymeleaf 的新手,我做了以下事情:

<div th:each="top : ${topic}">
    <input type="checkbox" th:field="*{topic}" th:checked="${top.checked}" th:value="${top.name}"/><label th:text="${top.name}">Something is wrong !</label>
</div>

我确信 Controller 和 Hibernate/MySQL 部分工作正常(我使用日志检查过)。

这很好用 - 但前提是我只 select 选中了一个复选框(最初是在我添加风险时)。

如果我 select 有多个复选框(添加风险时),后来 select 编辑此风险时不会选中任何复选框。

怎么了?

经过一些研究,我在 Thymeleaf 的文档中发现了以下文本:

“……th:field 会处理好这一点,并会在相应的输入标签中添加一个 checked="checked" 属性。”.

我也找到了这个指南:

http://forum.thymeleaf.org/The-checked-attribute-of-the-checkbox-is-not-set-in-th-each-td3043675.html

然后我设法开发了几个小应用程序,我想分享我的发现,希望它能帮助别人。 (可能对有经验的人来说太详细了,但我希望大家都清楚)

我不想重复上面提到的 Thymeleaf 论坛页面中已有的内容(详情请参阅管理员的第一个回复/解释 - 论坛主题中的第二个)- 只想做一个小总结并强调几点:

  • 使用th:each;

  • 确实不需要加checked
  • 您必须添加 th:field=“{...}”,它应该具有您模型中字段的名称 class(Thymeleaf 将其称为表单支持 bean - th:object ) 与复选框相关。有关此的更多信息:我在上面说过我的“表单支持 bean”是 Risk.java。对于每个 Risk 对象实例,selected 复选框表示特定于该 Risk 实例的主题。并且 selected 主题被分配给 Risk.java 实例的字段“主题”(因此在保存实例时在 MySQL 中的相关 table 中)。在我的例子中,该字段的名称应该放在 th:field=“{…}” 中,因为 th:field=“*{topic}”。当您 select 复选框时,Thymeleaf 将使用其 setTopic 方法将 selected 值保存到 Risk.java 的主题字段,当它需要恢复视图时,Thymeleaf 将使用 Risk.getTopic 方法来获取有关早期 selected 项目的信息。

  • 复选框(或单选按钮)的所有值都应来自另一个来源 - 如果您需要一组静态复选框,或者如果您需要动态生成复选框,则可以是枚举使用 class(我的应用程序需要一组静态复选框,但我决定也尝试创建一个动态复选框 - 请参阅下面我的 Github 存储库的链接以查看我设法开发的代码).因此,对于我的应用程序,我创建了一个包含所有复选框值的枚举主题和包含所有单选按钮值的枚举类型。然后在你的控制器中 class 你应该将所有值添加到模型的属性中——我这样做是因为我使用了枚举:

    model.addAttribute("topics", Topics.values());
    model.addAttribute("types", Types.values());
    

(如果您需要动态的,请执行以下操作:

    model.addAttribute("topics", topicsService.findAll());
    model.addAttribute("types", typesService.findAll());

)

那么你应该有类似的东西:

    <div>
            <div th:each="top : ${topics}">
                <input type="checkbox" th:field="*{topic}"  th:value="${top.id}"/><label th:text=" | &nbsp; ${top.name}|">Something is wrong !</label>
            </div>
    </div>

    <div>
            <div th:each="typ : ${types}">
                <input type="radio" th:field="*{type}"  th:value="${typ.id}"/><label th:text="| &nbsp; ${typ.name} |">Something is wrong !</label>
            </div>
    </div>

其中:

  • 如前所述,th:field=“{topic}”对应于表格支持模型class - Risk.java的字段。 th:field=“{type}” ;

  • 相同
  • th:each="top : ${topics}" 中的主题应与您在控制器中提供的属性名称匹配。

最重要的部分是 th:field=“*{topic}” 应该 return 一个数组。

th:field=“*{topic}” returning 一个 selected 项目的数组和 th:each returning 所有选项的数组 Thymeleaf当第一个数组中的值与第二个数组中的值匹配时,现在应该能够将复选框/单选按钮标记为已选中。

因为在单选按钮的情况下你可以 select 只有一个选项 th:field=“*{type}” 实际上 return 不是一个数组 - 它 return只有一件。但在复选框的情况下,它应该是一个数组 - 所以 Risk.java 中的“主题”字段必须 return 一个数组。

为此我们需要一个转换器 - 一个 class 命名为例如实现 AttributeConverter 的 StringListConverter….

( 我在这里学会了如何做。如果不是 www.whosebug.com 中的这个答案,我将无法完成这个应用程序,也不会写下所有这些: )

然后在你的表单支持模型中 class - Risk.java 在我的例子中你需要做类似的事情:

@Convert(converter = StringListConverter.class)
private List<String> topic = new ArrayList<>();

private String type;

类型可以是字符串。

就是这样。

( 我想在 table 表单中显示复选框,指示所需的列数 - 我可以做到,但我不确定它有多干净或有多安全。相关代码在 riskformtable.html 在下面链接的示例项目中。

我在这里发布了一个相关问题 - Thymeleaf - Displaying checkboxes in table form when using th:each - is what I am doing safe?

此外,我想对我的风险列表中具有偶数序号的所有风险项目使用不同的颜色 - 它在 index.html

使用下面的链接查看完整的示例代码)

指向我的 GitHub 存储库的链接: