2017 年 3 月 31 日,星期五

通过 Ajax 加载行详细信息

展示有关 DataTable 中某行的详细信息是一项热门功能。它允许最终用户以可访问的方式轻松处理主表格视图,同时还可让他们以结构化的方式深入查询更详细的数据。

DataTables 提供子行 API 方法 (row().child()row().child().show() 等),让你可以轻松显示类似的详细行。此网站上甚至还有一个简单示例

此博文的主题是建立在该示例的基础之上,说明如何处理一个简单但通常请求的扩展:通过 Ajax 方式异步加载子行数据,而不是仅仅使用表中的已有数据。

示例

下表显示了我们将在此文中构建的一个示例。单击显示图标将显示“正在加载”消息,然后此消息会被从服务器 Ajax 加载的数据替换掉。在此演示中,已将服务器端脚本中添加了两秒的人为延迟,这样你就可以看到加载消息,然后看到该消息被加载的信息所替换掉。

姓名 职位 办公室 工资
姓名 职位 办公室 工资

设置

此博文的大部分内容实际上是有关 DataTable 的基本设置,因为其最终实现可能出乎意料地简单。如果你已经熟练创建 DataTable,请跳到“Ajax 请求”部分。

基本 DataTable

让我们从头开始,创建一个使用通过 Ajax 获取数据且使用对象作为数据源的 DataTable

var table = $('#myTable').DataTable( {
    ajax: '/api/staff',
    columns: [
        {
            className:      'details-control',
            orderable:      false,
            data:           null,
            defaultContent: ''
        },
        { data: "name" },
        { data: "position" },
        { data: "office" },
        { data: "salary" }
    ],
    order: [[1, 'asc']]
} );

请注意,表中的第一列有为其分配一个类,并且仅仅显示一个空字符串(即无内容!)作为其数据值。这样做是为了能够将该单元格用作打开/关闭图标,让最终用户单击该图标以显示详细行。

事件处理程序

我们可以附加以下事件侦听器来执行打开/关闭操作

$('#myTable tbody').on('click', 'td.details-control', function () {
    var tr = $(this).closest('tr');
    var row = table.row( tr );

    if ( row.child.isShown() ) {
        row.child.hide();
        tr.removeClass('shown');
    }
    else {
        row.child( format(row.data()) ).show();
        tr.addClass('shown');
    }
} );

在上述代码中,我们使用row().child.isShown()来检查行是否有已显示的子行。如果有,则使用row().child.hide()将其隐藏;如果还没有,则使用row().child().show()来创建该子行。

整篇文章的主旨围绕着后者的这一功能!最简单的情况下,你可以给 row().child() 传递一个字符串,它会在子行中显示该字符串,但更重要的是,你还可以传入一个节点(或包含一个节点的 jQuery 对象),该节点将在表格中显示。这样一来,只要我们保留对该节点的引用,就可以在 Ajax 请求完成后,非常方便地更新文档。

Ajax 请求

我们的目标是创建一个 Ajax 请求,其响应将决定在详细信息行中显示的内容。当数据正在加载时,我们要向最终用户显示“Loading”消息,以便他们知道正在发生某些事情。我们可以利用 JavaScript 中一项非常强大的功能来实现,作为 JavaScript 开发人员,我们经常使用这项功能,但并不总是给它起个名称:闭包

你会注意到,在第 10 行事件处理程序代码中,我们调用了一个名为 format 的自定义函数(使用任何你想要的函数名!)并将行数据传递进去 - 我们想做的是,让它向 DataTables 返回带有加载消息的元素,以便它能立即显示,同时创建一个 Ajax 请求,在数据加载后更新该元素。

function format ( rowData ) {
    var div = $('<div/>')
        .addClass( 'loading' )
        .text( 'Loading...' );

    $.ajax( {
        url: '/api/staff/details',
        data: {
            name: rowData.name
        },
        dataType: 'json',
        success: function ( json ) {
            div
                .html( json.html )
                .removeClass( 'loading' );
        } 
    } );

    return div;
}

基本上就是这样!在子行中显示什么内容完全取决于你,因为它只是一个 div 容器元素。你可以使用动画显示它,插入另一个 DataTable,随你便!此处的关键是将 div 返回给子行进行呈现,同时利用 Ajax 和闭包来异步填充该 div