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

查看:40
本文介绍了Thymeleaf - 未在 th:each 中设置复选框的选中属性,或者如何正确恢复之前选中的复选框列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

稍后我想显示所有已添加风险的列表,每个风险上都有一个编辑选项按钮.我希望我的应用程序恢复特定于选定风险的视图(当单击选定风险上的编辑按钮时) - 风险名称、所有复选框和单选按钮都已选中,如先前选择的那样.我希望能够再次编辑这些复选框选择,以便所有新更改都正确反映在 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}">出了点问题!</label></div>

我确信 Controller 和 Hibernate/MySQL 部分工作正常(我使用 Logs 进行了检查).

这很好用——但前提是我只选择了一个复选框(最初是在我添加风险时).

如果我选择了多个复选框(添加风险时),然后选择此风险进行编辑,则不会选中任何复选框.

怎么了?

解决方案

经过一番研究,我在 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={...}" ,它应该具有模型类中的字段名称(Thymeleaf 称为 form-b​​acking bean - th:object )到哪个复选框有关系.更多信息:我在上面说过我的表单支持 bean"是 Risk.java.对于每个风险对象实例,选中的复选框代表特定于该风险实例的主题.并将选定的主题分配给 Risk.java 实例的字段主题"(因此在保存实例时在 MySQL 的相关表中).在我的例子中,该字段的名称应该在 th:field={...}" 中作为 th:field=*{topic}".当您选中复选框时,Thymeleaf 将使用其 setTopic 方法将选定的值保存到 Risk.java 的主题字段中,并且当它需要恢复视图时,Thymeleaf 将使用 Risk.getTopic 方法来获取有关先前选定项目的信息.

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

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

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

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

)

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

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

<div th:each="typ : ${types}"><input type="radio" th:field="*{type}" th:value="${typ.id}"/><label th:text="| &nbsp; ${typ.name} |">出了点问题!</label></div></div>

地点:

  • 如前所述,th:field="{topic}" 对应于表单支持模型类 - Risk.java 的字段.th:field="{type}" 相同;

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

最重要的部分是 th:field="*{topic}" 应该返回一个数组.

th:field=*{topic}" 返回一个选定项目数组和 th:each 返回所有选项数组 Thymeleaf 现在应该能够在第一个数组中的值与第二个数组中的值匹配时将复选框/单选按钮标记为选中数组.

因为在单选按钮的情况下,您只能选择一个选项 th:field=*{type}" 实际上并没有返回一个数组 - 它只返回一个项目.但在复选框的情况下,它应该是一个数组 - 因此 Risk.java 中的主题"字段必须返回一个数组.

为此,我们需要一个转换器——一个名为例如的类.实现 AttributeConverter 的 StringListConverter….

(我在这里学到了如何做到这一点.如果不是 www.stackoverflow.com 中的这个答案,我将无法最终确定这个应用程序,也不会写下所有这些:https://stackoverflow.com/a/34061723/6332774)

然后在您的表单支持模型类中 - 在我的情况下为 Risk.java 您需要执行以下操作:

@Convert(converter = StringListConverter.class)私有列表<字符串>主题 = 新的 ArrayList<>();私有字符串类型;

类型可以简单地是一个字符串.

就是这样.

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

我在这里发布了一个相关问题 - Thymeleaf - 使用 th:each 时以表格形式显示复选框 - 我这样做安全吗?

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

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

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

In my app I want to create a new Risk ( an instance of Risk object ) and when it is created I want to display 5 checkboxes and three radio buttons. Selected options are specific to each instance of Risk object.

Later I want to display a list of all added Risks with an Edit option button on each Risk. I want my app to restore the view specific to a selected Risk ( when an Edit button on a selected risk is clicked ) - with Risk name, all checkboxes and radio-buttons checked as selected previously. And I want to be able to edit these checkbox selections again so that all new changes were properly reflected in MySQL.

As a newbie in Thymeleaf I did the following:

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

I am sure that Controller and Hibernate/MySQL part works properly ( I checked using Logs ).

This works just fine - but only if I have selected only one checkbox ( initially when I added a risk ).

If I select more than one checkbox (when adding a risk) and later select this risk for editing no checkboxes are checked.

What is wrong ?

解决方案

After some research I found the following text in Thymeleaf’s documentation:

"… th:field would have taken care of that and would have added a checked="checked" attribute to the corresponding input tags.".

Also I found this guidance :

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

Then I managed to develop a couple of small apps and I want to share what I found out and hope it will help someone. ( may be it is too detailed for experienced people, but I want it to be clear to all )

I do not want to repeat what is already in the above-mentioned Thymeleaf’s forum page ( see Administrator’s first response / explanation for detail - second in forum thread ) - just want to make a small summary and stress out few points:

  • you indeed do not need to add ‘checked’ when using th:each;

  • you must add th:field="{…}" which should have the name of the field in your model class (referred by Thymeleaf as form-backing bean - th:object ) to which checkboxes are related. More on this: I stated above that my ‘form-backing bean’ was Risk.java. And for each Risk object instance the selected checkboxes represent topics(s) specific to this Risk instance. And selected topics are assigned to field ‘topic’ of Risk.java's instance (and hence in related table in MySQL when instance is saved). That field’s name should go inside th:field="{…}" as th:field="*{topic}" in my case. When you select checkboxes Thymeleaf will save selected values to Risk.java’s topic field using its setTopic method and when it needs to restore view Thymeleaf will use Risk.getTopic method to get info on earlier selected items.

  • all values of checkboxes (or radio-buttons ) should come from another source - it could be an Enum if you need a static set of checkboxes or if you need checkboxes to be dynamically generated you can use a class ( I needed static set of checkboxes for my app, but I decided to try to create a dynamic one as well - see links to my Github repo’s below to see the code I managed to develop ). So for my app I created an Enum Topics with all values for checkboxes and Enum Types with all values for radio-buttons. Then in your controller class you should add all values to Model’s attribute - I did this as I used an Enum:

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

(if you need dynamic ones do the following:

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

)

Then you should have something similar to:

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

where:

  • as mentioned, th:field="{topic}" corresponds to form-backing Model class - Risk.java’s field. Same for th:field="{type}" ;

  • topics in th:each="top : ${topics}" should match with attribute name you provided in controller.

And the MOST important part is that th:field="*{topic}" should return an array.

th:field="*{topic}" returning an array of selected items and th:each returning array of all options Thymeleaf should now be able to mark checkboxes / radio buttons as checked when values in first array match values in second array.

Since in case of radio buttons you can select only one option th:field="*{type}" does not actually return an array - it returns only one item. But in case of checkboxes it should be an array - so the ‘topic’ field in Risk.java must return an array.

For this we need a converter - a class named e.g. StringListConverter that implements AttributeConverter….

( I learned how I can do it here. If not this answer in www.stackoverflow.com I would not be able to finalyze this app and would not be writing all this: https://stackoverflow.com/a/34061723/6332774 )

Then in your form-backing model class - Risk.java in my case you need to do something like :

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

private String type;

Type can simply be a String.

That is it.

( I wanted to display checkboxes in table form indicating number of columns needed - I could do it, but I am not sure how clean it is or how safe it is. Related code is in riskformtable.html in example project linked below.

I posted a related question here - Thymeleaf - Displaying checkboxes in table form when using th:each - is what I am doing safe?

Also I wanted to use different color for all risk items with even sequential number in my risk’s list - it is in index.html

See full example code using links below )

Links to my GitHub repos:

这篇关于Thymeleaf - 未在 th:each 中设置复选框的选中属性,或者如何正确恢复之前选中的复选框列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆