dataTables内嵌二级表格的实现

之前在写angular时有用过ui-grid写过内嵌展开二级表格,怎么说呢,ui-grid很强大,功能挺多的,好像也是angular团队开发的,例子足,文档好(对那些英文阅读能力比较好的人来说),不过他的有些功能不稳定,其中就包括表格中内嵌表格的实现Expandable grid

之后在写别的项目时也遇到了相同的需求,这次准备使用datatables,在此记录下过程。

直接上代码:

html部分

//这个div用来存放查询条件
<div>
    <div class="float-left m-b-md"><label>账户名:</label><input id="accountName" type="text"></div>
    <div class="float-left m-b-md"><label>银行账号:</label><input id="bankAccount" type="text"></div>
    <div class="float-left m-b-md"><label>账户ID:</label><input id="accountId" type="text"></div>
    
    <button id="searchBtn" class="m-b-md">查询</button>
</div>
//以下是table的主体
<table id="example" class="display" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th></th>
            <th>账户ID</th>
            <th>账户名</th>
            <th>账户状态</th>
            <th>账户类型</th>
            <th>账户余额</th>
            <th>银行账号</th>
            <th>冻结金额</th>
            <th>在途金额</th>
            <th>最后交易时间</th>
            
            
        </tr>
    </thead>
</table>

html部分分为搜索部分和table主体部分,挺简单的没啥说的

js部分

    //1.初始化部分
    //1.1禁用表格自带的搜索和排序
    $.extend($.fn.dataTable.defaults, {
        searching: false,
        ordering: false
    });
    //1.2初始化表格主体
    var table = $('#example').DataTable({
    //配置相应部分的中文显示(废话,不然就显示英文了)
        "language": {
            "lengthMenu": "每页 _MENU_ 条记录",
            "zeroRecords": "没有找到记录",
            "info": "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )",
            "infoEmpty": "无记录",
            "infoFiltered": "(从 _MAX_ 条记录过滤)",
            "paginate": {
                "first": "First",
                "last": "Last",
                "next": "后一页",
                "previous": "上一页"
            },
        },
    
        "pageLength": 10,           //默认每页条数
        "lengthChange": false,      //禁掉表格自带的选择每页条数的下拉框
        "processing": true,         //是否显示进度遮罩
        "serverSide": true,         //开启服务端传输数据
        "ajax": {                   //ajax
            url: "${ctx}/client/account/accountListData",
            type: "POST",
            data: function(d) {
                //获取查询条件的值
                var accountName  = $("#accountName").val();
                var bankAccount  = $("#bankAccount").val();
                var accountId  = $("#accountId").val();
                //添加额外的参数传给服务器  
                 d.accountName = accountName;
                 d.bankAccountNo = bankAccount;
                 d.accountId = accountId;
            },
            
        },
        //这里虽然没用到,但这个属性很有用,可以初始datatable的data(还是去看看官网吧),因为插件对返回值的格式要求严格
        /* "dataSrc": function(json){
               
               return json.data[0].body.records;
            }, */
        //配置各列
        "columns": [{
            className: 'details-control',   //就是给这列添加的类名
            orderable: false,               //禁用掉这列的排序功能
            data: null,                  //data为空,因为这列只有展开icon
            defaultContent: ''          //没数据的话为空
            },{
            data:'accountId'
                /* "targets": 0,
                "data": "body",
                "render": function ( data, type, full, meta ) {
                  return data.records.memberId;
                } */
            },{
            data: 'accountName'
            },{
            data: 'accountStatusdic'
            },{
            data: 'accounTypedic'
            },{
            data: 'availableBalance'
            },{
            data: 'bankAccount'
            },{
            data: 'freezeBalance'
            },{
            data: 'undeterminedBalance'
            },/* {
            data: 'memberId',
            },{
            data: 'memberStatusDic',  
            }, */{
             data: 'lastTranTime'
            }
            ],
        "columnDefs": [
            {
                targets: [5, 7, 8 ],  //这个用于对列的批量处理,里面为需要处理的列的下标
                //render很有用,这里主要是过滤用,好像在columns中也可以写render
                render: function(data,type,row,meta){
                    return ("¥"+data.toFixed(2));
                }
            },
            
         ] 
    });
    //点击查询,触发表格的渲染
    $("#searchBtn").click(function() {
        table.ajax.reload();
    });
    //二级table的模板
    function format(table_id) {
        return '<table class="table table-striped" id="opiniondt_' + table_id + '">' +
        '<thead>'+
        '<tr>'+
        '<th>账户ID</th><th>账户名</th><th>账户状态</th>'+
        '<th>账户类型</th><th>可用余额</th><th>冻结金额 </th>'+
        '<th>最后交易时间</th><th>锁定金额</th><th>在途金额</th>'+
        '</tr>'+
        '</thead>' +
        '<tr>' +
        '<td>Full name:</td>' +
        '<td>Extension number:</td>' +
        '<td>Extra info:</td>' +
        '</tr>' +
        '<tr>' +
        '<td>Full name:</td>' +
        '<td>Extension number:</td>' +
        '<td>Extra info:</td>' +
        '</tr>' +
        '</table>';
    }
    //先初始化一个变量,用于动态给展开的二级table赋值
    var iTableCounter = 1;
    var oInnerTable;
    //展开icon的点击事件
    $('#example tbody').on('click', 'td.details-control', function() {
        //获得最近的tr老爸
        var tr = $(this).closest('tr');
        //遍历老铁们
        var td = $(this).siblings("td");
        //获取第一个老铁的内容
        var acId=td[0].innerHTML;
        
        //把选择的这一行变成datatable的行,这样就可以使用一些方法了
        //dataTables默认给所有的行设置了他们的子显示区
        //可通过row().child.show()和row().child.hide()显示隐藏
        var row = table.row(tr);
        
        var data;
        if (row.child.isShown()) {
            //  This row is already open - close it
            row.child.hide();
            //这个shown是为了控制展开icon和收缩icon的切换显示
            tr.removeClass('shown');
        } else {
            //ajax开始传参给后台
              $.ajax({
                url:"${ctx}/client/account/getSlaveAccount",
                type:"POST",
                data:{accountId:acId},
            }).done(function(res){
                data = JSON.parse(res);
                //这里是请求后台字典接口,进行过滤数据,记住设置为同步请求
                data.slaveAccounts.forEach(function(e){
                    (function(){
                    $.ajax({
                        url:"${ctx}/client/dict/getDicValue",
                        type:"post",
                        async:false,
                        data:{
                            type:"accountType",
                            value:e.accountType,
                            defaultValue:""
                        }
                    }).done(function(res1){
                        e.accountType=res1;
                    });
                }());
                    //处理accountStatus
                    (function(){
                    $.ajax({
                        url:"${ctx}/client/dict/getDicValue",
                        type:"post",
                        async:false,
                        data:{
                            type:"accountStatus",
                            value:e.accountStatus,
                            defaultValue:""
                        }
                    }).done(function(res2){
                        e.accountStatus=res2;
                    });
                    }());
                })
                var lastData=data.slaveAccounts;
                // Open this row
                //child()内接收二级table的模板
                row.child(format(iTableCounter)).show();
                //显示出收缩icon
                tr.addClass('shown');
                // try datatable stuff
                //为所有的二级列表配置
                oInnerTable = $('#opiniondt_' + iTableCounter).dataTable({
                    data: lastData,
                    autoWidth: true,
                    deferRender: true,
                    info: false,
                    lengthChange: false,
                    ordering: false,
                    paging: false,
                    scrollX: false,
                    scrollY: false,
                    searching: false,
                    columns: [{
                        data: 'accountId'
                    }, {
                        data: 'accountName'
                    }, {
                        data: 'accountStatus'
                    }, {
                        data: 'accountType'
                    }, {
                        data: 'availableBalance'
                    }, {
                        data: 'freezeBalance'
                    }, {
                        data: 'lastTranTime'
                    }, {
                        data: 'lockBalance'
                    }, {
                        data: 'undeterminedBalance'
                    }],
                    columnDefs: [{
                        targets: [4,5, 7, 8 ],
                        render: function(data,type,row,meta){
                                    return ("¥"+data.toFixed(2));
                                }
                    }] 
                });
                //+1后下一个展开的二级table的id加1
                iTableCounter = iTableCounter + 1;
            })  
        }
    })

嗯,想说的过程全变成注释了,就酱吧。

别的东西

从别处访问获得的json数据

2017.06.09,之后遇到了这个问题,去查了下文档,在datatable配置内可通过this.api().ajax.json()访问获得的json数据

其实this指向的就是table

操作行数据

一般是写在监听事件的处理函数中的,如下,获取触发点击事件哪一行的数据
table.row( this ).data()