首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用ajax的带有子行的出色datatable

使用ajax的带有子行的出色datatable
EN

Stack Overflow用户
提问于 2014-05-13 23:31:42
回答 1查看 11.5K关注 0票数 8

我正在尝试使用datatables库来实现更多的定制。

这是我正在尝试制作的示例。https://datatables.net/examples/api/row_details.html请注意,我在不同的data.frame R变量中有详细信息。像这样

代码语言:javascript
运行
复制
A= data.frame(Name = c("Airi Satou", "Angelica Ramos","Paul Byrd")
               , Position = c("Accountant","Accountant", "CEO")
               , Office   = c("Tokyo", "Tokyo", "New York"))
A.detail= data.frame(Name = c("Airi Satou", "Angelica Ramos")
               , Extension= c("5407c", "8422")
               , salary   = c(16000, 20000))

我不喜欢合并两个data.frame变量,如果可以不合并的话,因为计算时间太长。显然,有些行可能没有任何细节。

我可以在数据表中选择一行,并通过绑定该行作为输入将行信息发送到R(多亏了https://github.com/toXXIc/datatables.Selectable/),然后我可以从第二个data.frame变量中找到与R中选定行相关的详细信息。但我不知道如何将其发送回html (在选定的行下)上显示。我已经将第一个表绑定为shinyoutput,所以我不确定是否可以传递另一个数据来再次更改此输出。

也许我应该在点击detail按钮时使用ajax来请求更多的数据,但是我不知道如何在shiny中进行ajax请求。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-08-07 00:43:13

在回答您的问题之前,我想指出,CRAN上当前版本的DataTables.js (0.10.1)使用的是旧版本的DataTables.js (1.0.9),而您提到的示例使用的是CRAN 1.10。在DataTables 1.10中,有相当一部分API与1.0.9版不兼容。

你可以在Github:https://github.com/rstudio/shiny/pull/558上查看这个拉取请求,它提供了对DataTables.js 1.10的支持。

首先,让我们稍微离题一下,了解一下数据表是如何在Shiny中呈现的。

该示例使用AJAX请求从服务器URL“拉取”数据,随后将数据绑定到表模板。这就是所谓的服务器端数据渲染。

Shiny还使用服务器端数据呈现。然而,您提供的示例与Shiny之间的主要区别在于Shiny中的数据传输对您是透明的。

从技术上讲,Shiny通过调用shiny:::registerDataObj()为AJAX请求创建了一个JSON API。您可以在此处找到构造自定义AJAX请求的示例:http://shiny.rstudio.com/gallery/selectize-rendering-methods.html

示例和Shiny之间的另一个不同之处在于它们如何将表内容编码到JSON blob中。该示例使用纯对象对每一行进行编码。例如,第一行编码为:

{ "name": "Tiger Nixon", "position": "System Architect", "salary": "$320,800", "start_date": "2011\/04\/25", "office": "Edinburgh", "extn": "5421" },

而Shiny将data.frame的每一行编码为数组,例如,

["Tiger Nixon", "System Architect", "$320,800", "2011\/04\/25", "Edinburgh", "5421"]

原始 JSON数据的差异会影响我们稍后如何实现format()函数。

最后,该示例使用固定的HTML <table>模板来呈现数据表。您可能已经注意到,模板中只包含可见的列(例如,分机号码列不在<table>模板中);而Shiny会为您创建模板,而您不必决定如何执行数据绑定(例如{ "data": "name" },)。

注意:下面的R代码使用Shiny的开发分支,您可以在上面的拉取请求链接中找到该分支。

尽管我们不能决定将哪些列绑定到什么数据,但我们可以通过在调用DataTable()函数时指定columnDefs选项来选择隐藏哪些列。您可以通过将https://datatables.net/reference/option/中定义的任何选项包装在R中的list中来传递这些选项。

一个使用示例数据的闪亮应用程序示例如下:

ui.R

代码语言:javascript
运行
复制
library(shiny)

format.func <- "
<script type='text/javascript'>
function format ( d ) {
    return '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">'+
        '<tr>'+
            '<td>Full name:</td>'+
            '<td>'+d[1]+'</td>'+
        '</tr>'+
        '<tr>'+
            '<td>Extension number:</td>'+
            '<td>'+d[4]+'</td>'+
        '</tr>'+
    '</table>';
}
</script>
"

shinyUI(
    fluidPage(
        h5("Data table"),
        dataTableOutput("dt"),
        tags$head(HTML(format.func))
    ) 
)

这里没有什么特别之处,只是我相应地更改了format()函数,因为如前所述,Shiny以行数组而不是对象的形式发送数据。

server.R

代码语言:javascript
运行
复制
library(shiny)
library(dplyr)

shinyServer(function(input, output, session) {
    A <- data.frame(Name = c("Airi Satou", "Angelica Ramos","Paul Byrd"),
                  Position = c("Accountant","Accountant", "CEO"),
                  Office   = c("Tokyo", "Tokyo", "New York"))

    A.detail <- data.frame(Name = c("Airi Satou", "Angelica Ramos"),
                          Extension = c("5407c", "8422"),
                          Salary    = c(16000, 20000))

    # You don't necessarily need to use left_join. You can simply put every column,
    # including the columns you would by default to hide, in a data.frame.
    # Then later choose which to hide.
    # Here an empty column is appended to the left to mimic the "click to expand"
    # function you've seen in the example.
    A.joined <- cbind("", left_join(A, A.detail, by="Name"))

    columns.to.hide <- c("Extension", "Salary")
    # Javascript uses 0-based index
    columns.idx.hidden <- which(names(A.joined) %in% columns.to.hide) - 1

    # Everytime a table is redrawn (can be triggered by sorting, searching and 
    # pagination), rebind the click event.

    draw.callback <- "
function(settings) {
    var api = this.api();
    var callback = (function($api) {
        return function() {
            var tr = $(this).parent();
            var row = $api.row(tr);
            if (row.child.isShown()) {
                row.child.hide();
                tr.removeClass('shown');
            }
            else {
                row.child(format(row.data())).show();
                tr.addClass('shown');
            }
        }
    })(api);

    $(this).on('click', 'td.details-control', callback);
}"
    # wrap all options you would like to specify in options=list(),
    # which will be converted into corresponding JSON object.
    output$dt <- renderDataTable(A.joined,
        options=list(
            searching=F,
            columnDefs=list(
                            list(targets=0,
                                 title="", class="details-control"),
                            list(targets=columns.idx.hidden,
                                 visible=F)
                         ),
            drawCallback=I(draw.callback)
    ))
})

现在,如果您单击数据表的第一个(空)列(因为我没有编写CSS),您应该能够在展开区域中看到显示的额外信息。

编辑:延迟加载“更多细节”信息

上面的解决方案涉及将所有信息发送到客户端,尽管在大多数使用情况下,用户可能不会费心查看隐藏的信息。从本质上讲,我们最终会向客户端发送大量冗余数据。

一个更好的解决方案是在Shiny中实现一个AJAX请求处理程序,它只在需要时(即用户请求时)返回信息。

要实现AJAX请求处理程序,可以使用session$registerDataObj。此函数在唯一的 URL上注册请求处理程序,并返回此URL。

为了调用这个已注册的请求处理程序,您需要首先将此AJAX URL发送到客户端。

下面我破解了一个快速的解决方案:基本上,你可以在网页上创建一个隐藏的<input>元素,在这个元素上你可以绑定一个change事件侦听器。Shiny服务器通过函数调用session$sendInputMessage向客户机发送一条消息来更新这个<input>元素的值。收到消息后,它会更改<input>元素的值,从而触发事件侦听器。然后,我们可以正确地设置AJAX请求URL

然后,您可以发起任何普通的AJAX请求来获取所需的数据。

ui.R

代码语言:javascript
运行
复制
library(shiny)

format.func <- "
<script type='text/javascript'>
var _ajax_url = null;

function format ( d ) {
    // `d` is the original data object for the row
    return '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">'+
        '<tr>'+
            '<td>Full name:</td>'+
            '<td>'+d.Name+'</td>'+
        '</tr>'+
        '<tr>'+
            '<td>Extension number:</td>'+
            '<td>'+d.Extension+'</td>'+
        '</tr>'+
    '</table>';
}

$(document).ready(function() {
  $('#ajax_req_url').on('change', function() { _ajax_url = $(this).val()});
})
</script>
"

shinyUI(
    fluidPage(
        # create a hidden input element to receive AJAX request URL
        tags$input(id="ajax_req_url", type="text", value="", class="shiny-bound-input", style="display:none;"),

        h5("Data table"),
        dataTableOutput("dt"),
        tags$head(HTML(format.func))
    ) 
)

server.R

代码语言:javascript
运行
复制
library(shiny)
library(dplyr)

shinyServer(function(input, output, session) {
    # extra more.details dummy column
    A <- data.frame(more.details="", Name = c("Airi Satou", "Angelica Ramos","Paul Byrd"),
                  Position = c("Accountant","Accountant", "CEO"),
                  Office   = c("Tokyo", "Tokyo", "New York"))

    A.detail <- data.frame(Name = c("Airi Satou", "Angelica Ramos"),
                          Extension = c("5407c", "8422"),
                          Salary    = c(16000, 20000))

    draw.callback <- "
function(settings) {
    var api = this.api();
    var callback = (function($api) {
        return function() {
            var tr = $(this).parent();
            var row = $api.row(tr);
            if (row.child.isShown()) {
                row.child.hide();
                tr.removeClass('shown');
            }
            else {
                // we can use the unique ajax request URL to get the extra information.
                $.ajax(_ajax_url, {
                  data: {name: row.data()[1]},
                  success: function(res) { 
                      row.child(format(res)).show(); 
                      tr.addClass('shown');
                  }
                });
            }
        }
    })(api);

    $(this).on('click', 'td.details-control', callback);
}"

    ajax_url <- session$registerDataObj(
      name = "detail_ajax_handler", # an arbitrary name for the AJAX request handler
      data = A.detail,  # binds your data
      filter = function(data, req) {
        query <- parseQueryString(req$QUERY_STRING)
        name <- query$name

        # pack data into JSON and send.
        shiny:::httpResponse(
          200, "application/json", 
          # use as.list to convert a single row into a JSON Plain Object, easier to parse at client side
          RJSONIO:::toJSON(as.list(data[data$Name == name, ]))
        )        
      }
    )

    # send this UNIQUE ajax request URL to client
    session$sendInputMessage("ajax_req_url", list(value=ajax_url))

    output$dt <- renderDataTable(A,
        options=list(
            searching=F,
            columnDefs=list(
                            list(targets=0,
                                 title="", class="details-control")
                         ),
            drawCallback=I(draw.callback)
    ))
})
票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23635552

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档