最近在Thymeleaf做一个页面的时候,因为需要使用List循环展示,提交List到后端,出现各种问题,解决起来也不甚痛苦,这里把解决问题的方式分享一下,也便于自己记录。

介绍:

需求是前端页面循环展示一个后端来的数据,并且前端循环的列表每个都有点击事件,需要把列表中的自己的id传入到触发事件中,最后提交的时候把循环列表的数据全部提交到后端。
我使用的是SpringBoot+Thymeleaf,下面用代码一步步展示过程

1.开始的页面,简单的展示(无循环)

前端:

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <th:block th:include="include :: header('申请预约(未预约)列表')" />
    <th:block th:include="include :: datetimepicker-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
    <form class="form-horizontal m" id="form-schapplication-add">
        <div class="form-group">
            <label class="col-sm-3 control-label">申请时间:</label>
            <div class="col-sm-8">
                <div class="input-group date">
                    <input name="appTime" th:value="${#dates.format(schInsTime, 'yyyy-MM-dd hh:mm')}" id="appTime" class="form-control" placeholder="yyyy-MM-dd" type="text" th:data-insItemId="${insItemId}">
                    <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
                </div>
            </div>
        </div>
    </form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: datetimepicker-js" />
<script th:inline="javascript">
    var prefix = ctx + "schmanage/schapplication"
    $("#form-schapplication-add").validate({
        focusCleanup: true
    });

    $("input[name='appTime']").datetimepicker({
        // format: "yyyy-mm-dd",
        language: "ja",
        format: "yyyy-mm-dd  HH:ii",
        // minView: "month",
        minView: 0,
        autoclose: true,
        minuteStep:10
    }).on('changeDate',function(event){
        console.log(event.date);
        // $.operate.post(prefix+"/activeInsTime",{'insActiveTime':event.date});
    });
</script>
</body>
</html>

后端:

@RequestMapping( "/getSchInsTimeByItemsId")
    public String getSchInsTimeByItemsId(String insItemsId,ModelMap mmap){
        mmap.put("schInsTime", scheduledApplicationService.getSchInsTimeByItemsId(insItemsId));
        mmap.put("insItemId", insItemsId);
        return prefix + "/schInsTime";
    }

上面是一个简单的跳转页面,展示ModelMap 里的数据的无循环的。url访问xxx/getSchInsTimeByItemsId?insItemsId=xxx 即可跳转到前端页面,如下图

 2.接着需求 需要改成循环列表展示,并且实现可以点击循环的列表,并将其中的id传入触发事件,(贴上前端代码和后端的Controller和实体类代码)

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <th:block th:include="include :: header('申请预约(未预约)列表')" />
    <th:block th:include="include :: datetimepicker-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
    <form class="form-horizontal m" id="form-schapplication-add" action="/schmanage/schapplication/test" >

        <div class="form-group" id="schAppLication" th:each="schAppInsItem,schAppInsItemStat:${schAppInsVOs}">
            <label class="col-sm-3 control-label"><span th:text="${schAppInsItem.insItemsName}"> </span></label>
            <div class="col-sm-8">
                <div class="input-group date">
                    <!--这里要把循环的id取到传入触发事件中,需要写上this.getAttribute(xxx),并且要写th:data-xxx -->
                    <input  th:name="applicationTime" th:value="${#dates.format(schAppInsItem.applicationTime, 'yyyy-MM-dd HH:mm')}" id="appTime" class="form-control" placeholder="yyyy-MM-dd" type="text" th:data-insItemsId="${schAppInsItem.insItemsId}" th:onchange="|changeAppTime(value,this.getAttribute('data-insItemsId'),${schAppInsItemStat.index})|">
                    <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
                </div>
            </div>
        </div>
    </form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: datetimepicker-js" />
<script th:inline="javascript">
    var prefix = ctx + "schmanage/schapplication"
    $("#form-schapplication-add").validate({
        focusCleanup: true
    });

    function submitHandler() {
        if ($.validate.form()) {
            $.operate.save(prefix + "/add", $('#form-schapplication-add').serialize());
        }
    }

    $("input[name='applicationTime']").datetimepicker({
        // format: "yyyy-mm-dd",
        language: "ja",
        format: "yyyy-mm-dd hh:ii",
        // minView: "month",
        minView: 0,
        autoclose: true,
        minuteStep:10
    })
    //触发改变事件
    function changeAppTime(appTime,insItemId,index){
        console.log(appTime)
        $.operate.post(prefix+"/activeInsTime",{'insItemsId':insItemId,'insActiveTime':appTime},activeInsTime);
    }
    //callback方法,
    function activeInsTime(result) {
        console.log(result);
        if(result.code == web_status.WARNING){
            $("input[data-insItemsId="+result.data.insItemsId+"]").val(result.data.applicationTime);
        }
    }
</script>
</body>
</html>

@RequestMapping( "/schInsTimeToView")
    public String schInsTimeToView(@RequestParam  List<String> insItemsIds,ModelMap mmap){
        mmap.put("schAppInsVOs",scheduledApplicationService.schInsTimeToView(insItemsIds));
        return prefix + "/schInsTime";
    }



    @RequestMapping( "/activeInsTime")
    @ResponseBody
    public AjaxResult activeInsTime(String insItemsId,Date insActiveTime) throws Exception{
        Date resultActiveTime = scheduledApplicationService.activeInsTime(insItemsId, insActiveTime);
        if(resultActiveTime == null){
            return AjaxResult.success("该时间可以预约");
        }else{
            SchApplicationVO schApplicationVO = new SchApplicationVO();
            schApplicationVO.setApplicationTime(resultActiveTime);
            schApplicationVO.setInsItemsId(insItemsId);
            return AjaxResult.warn("该时间已被预约/不在上班时间,已为您调整至最近可预约时间",schApplicationVO);
        }
    }
//省略get,set
public class SchApplicationVO implements Serializable {

    /** 检查项目编码 */
    private String insItemsId;

    /** 检查项目名称 */
    private String insItemsName;

    private Date applicationTime;
}

 

动图有点不太会弄,凑合看看吧,目前实现了循环展示列表和改变列表中的任意一个都可以把他的id传参

3.最后需求需要改成 需要把选好的循环列表数据提交后端

这里需求后端接收对象集合,这里坑坑了我挺久,先总结下,首先后端需要把 想跟前端交互的对象装成一个List再封装到一个新的类中,前端需要改th:field进行绑定(当然也需要先用th:object解析),最后的最后,因为我这边是时间格式的,从后端过来的格式还需要处理下,具体看代码,在代码中我添加注释加以说明,最后的效果是前端点击提交,后端接收获取得到List数据

 后端代码 (Controller):
 

/**
     * 获取当前预约的能预约到的预约时间
     * @param insItemsIds 检查项目id集合
     * @return
     */
    @RequestMapping( "/schInsTimeToView")
    public String schInsTimeToView(@RequestParam  List<String> insItemsIds,ModelMap mmap){
        SchApplicationOutWap schApplicationOutWap = new SchApplicationOutWap();
        schApplicationOutWap.setList(scheduledApplicationService.schInsTimeToView(insItemsIds));
        mmap.put("schAppInsVOs",schApplicationOutWap);
        return prefix + "/schInsTime";
    }


    /**
     * 医生主动设置预约时间来预约
     * @param insItemsId 检查项目id
     * @param insActiveTime 主动申请预约时间
     */
    @RequestMapping( "/activeInsTime")
    @ResponseBody
    public AjaxResult activeInsTime(String insItemsId,Date insActiveTime) throws Exception{
        Date resultActiveTime = scheduledApplicationService.activeInsTime(insItemsId, insActiveTime);
        if(resultActiveTime == null){
            return AjaxResult.success("该时间可以预约");
        }else{
            SchApplicationVO schApplicationVO = new SchApplicationVO();
            schApplicationVO.setApplicationTime(resultActiveTime);
            schApplicationVO.setInsItemsId(insItemsId);
            return AjaxResult.warn("该时间已被预约/不在上班时间,已为您调整至最近可预约时间",schApplicationVO);
        }
    }


    /**
     * 确定预约   。前端点提交进入此方法。
     */
    @RequestMapping( "/test")
    @ResponseBody
    public AjaxResult test(SchApplicationOutWap list)
    {
        System.out.println(list.getList());
        return AjaxResult.success();
    }

这里我们可以看到 schInsTimeToView方法里面我改动了些,增加了SchApplicationOutWap  这个类里面一个外包裹,其实里面就是只有个List的SchApplicationVO的属性

Pojo

public class SchApplicationOutWap implements Serializable {
    private List<SchApplicationVO> list;

    //省略get set
}
//省略get,set
public class SchApplicationVO implements Serializable {

    /** 检查项目编码 */
    private String insItemsId;

    /** 检查项目名称 */
    private String insItemsName;
    // 加上这个可以让前端以此格式输出time
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone="GMT+8")
    private Date applicationTime;
}

后端想要接收SchApplicationVO对象集合,就必须在其外面再写个对象,像上面这样,才可以跟前端进行绑定(这里本人觉得...一言难尽的设计)

最后附上前端代码:

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <th:block th:include="include :: header('申请预约(未预约)列表')" />
    <th:block th:include="include :: datetimepicker-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">

<!-- 这里需要使用 th:object 把刚后端传来的对象解析出来-->
    <form class="form-horizontal m" id="form-schapplication-add"  th:object="${schAppInsVOs}">

        <div class="form-group" id="schAppLication" th:each="schAppInsItem,schAppInsItemStat:${schAppInsVOs.list}">
            <label class="col-sm-3 control-label"><span th:text="${schAppInsItem.insItemsName}"> </span></label>
            <div class="col-sm-8">
                <div class="input-group date" name="appInsItemDiv">
<!-- th:field 进行跟后端绑定, list对应的是后端SchApplicationOutWap 写的List<对象> 的属性名 
 .applicationTime 是这一行的数据是跟 后端对象里的applicationTime进行绑定,至此,此行不需要写name,因为name=xxx就是applicationTime,不需要写value=xxx,写了也没用,因为绑定了,不信你试试 -->
                    <input   th:field="*{list[__${schAppInsItemStat.index}__].applicationTime}" th:value="${#dates.format(schAppInsItem.applicationTime, 'yyyy-MM-dd HH:mm')}"  name="appTime" id="appTime" class="form-control" placeholder="yyyy-MM-dd" type="text" th:data-insItemsId="${schAppInsItem.insItemsId}" th:onchange="|changeAppTime(value,this.getAttribute('data-insItemsId'),${schAppInsItemStat.index})|">
                    <span class="input-group-addon"><i class="fa fa-calendar"></i></span>

                    <input type="hidden" th:field="*{list[__${schAppInsItemStat.index}__].insItemsId}" th:value="${schAppInsItem.insItemsId}">
                </div>
            </div>
        </div>
    </form>
    <button onclick="submitHandler()" >提交</button>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: datetimepicker-js" />
<script th:inline="javascript">
    var prefix = ctx + "schmanage/schapplication"
    $("#form-schapplication-add").validate({
        focusCleanup: true
    });
    function submitHandler() {

        console.log($('#form-schapplication-add').serialize());
        if ($.validate.form()) {
            $.operate.post(prefix + "/test", $('#form-schapplication-add').serialize());
        }
    }
        var a = [[${schAppInsVOs}]];
        console.log(a.list.length);
        //循环绑定事件,这里其实我也研究了挺久,不知道怎么给列表的每个绑定事件,最后只能用这个办法,如果有其他更好的方法,请不吝赐教
        for(var i=0;i<a.list.length;i++){
           
          $("input[name='list["+i+"].applicationTime']").val(a.list[i].applicationTime);
            $("input[name='list["+i+"].applicationTime'] " ).datetimepicker({
                // $("#appTime").datetimepicker({
                // format: "yyyy-mm-dd",
                language: "zh-CN",
                format: "yyyy-mm-dd  hh:ii",
                // minView: "month",
                minView: 0,
                autoclose: true,
                minuteStep:10
            })
        }
    

    function activeInsTime(result) {
        console.log(result);
        if(result.code == web_status.WARNING){

            $("input[data-insItemsId="+result.data.insItemsId+"]").val(result.data.applicationTime);
        }
    }

    function changeAppTime(appTime,insItemId,index){
        console.log(insItemId);
        console.log(appTime);
        console.log(index);

        $.operate.post(prefix+"/activeInsTime",{'insItemsId':insItemId,'insActiveTime':appTime},activeInsTime);
    }
    
</script>
</body>
</html>

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐