闪亮的数据表与孩子用ajax行 [英] Shiny datatable with child rows using ajax

查看:243
本文介绍了闪亮的数据表与孩子用ajax行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用数据表库光泽与更多的定制。

I'm trying to use datatables library for shiny with more customization.

下面是我想要做的例子。 https://datatables.net/examples/api/row_details.html 请注意,我在不同的data.frame R参数详细信息。像这样

Here is the example that I'm trying to make. https://datatables.net/examples/api/row_details.html Note that I have detail info in different data.frame R variables. like this

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变量,如果能够做到这一点没有合并,因为计算时间。显然,某些行可以不具有任何细节。

I don't like to merge two data.frame variables, if it is possible to do this without merge, because of the computation time. Obviously, some of rows may not have any details.

我可以选择行中的数据表,并结合该输入(感谢的 https://github.com/toXXIc/datatables.Selectable/ ) 然后,我可以找到相关的在R所选择行从第二data.frame变量的详细信息。 但我不知道如何发送这回展示的HTML(所选行下)。不敢肯定我是否可以通过另一个数据再次改变这个输出

I can select a row in data table and send the line information to R by binding this as input (thanks to https://github.com/toXXIc/datatables.Selectable/) Then I can find details relevant to selected line in R from the second data.frame variable. but I don't know how to send this back to show on the html (under the selected row). I already binded the first table as shinyoutput so I;m not sure if I can pass another data to change this output again.

也许我应该用ajax点击详细按钮时要求更多的数据,但我不知道该怎么办Ajax请求的光泽。

Maybe I should use ajax to request more data when detail button is clicked, but I don't know how to do ajax request in shiny.

推荐答案

在回答你的问题,我想指出的是闪亮的CRAN上的当前版本(0.10.1)使用DataTables.js的旧版本( 1.0.9),而比如你刚才提到使用DataTables.js 1.10。有相当大的比例的API在数据表1.10,它与1.0.9版本不兼容。

Before answering your questions, I would like to point out that the current version of Shiny (0.10.1) on CRAN uses an older version of DataTables.js (1.0.9), whereas the example you have mentioned uses DataTables.js 1.10. There is a considerable proportion of API in DataTables 1.10 that is incompatible with version 1.0.9.

您可以看看这个 pull请求 Github上: https://github.com/ rstudio /闪亮/拉/ 558 ,它提供DataTables.js 1.10的支持。

You can check out this pull request on Github: https://github.com/rstudio/shiny/pull/558 , which provides DataTables.js 1.10 support.

首先,让我们离题一点点地了解一个数据表中闪亮呈现。

First, let's digress a little bit to understand how a data table is rendered in Shiny.

该示例使用AJAX请求从服务器的URL拉的数据,并随后绑定数据表模板。这就是所谓的服务器端的数据呈现的。

The example uses AJAX request to "pull" data from a server URL, and subsequently binds the data to the table template. This is what so-called server-side data rendering.

闪亮也使用的服务器端的数据呈现的。但是,您所提供的例子,有光泽的主要区别是,在闪亮的传输数据是透明的你。

Shiny also uses server-side data rendering. However, the major difference between the example you've provided and Shiny, is that the data transferring in Shiny is transparent to you.

从技术上讲,在引擎盖下,闪亮致电创造了AJAX请求的JSON API 有光泽::: registerDataObj()。你可以在这里找到构建您的自定义AJAX请求的例子:<一href="http://shiny.rstudio.com/gallery/selectize-rendering-methods.html">http://shiny.rstudio.com/gallery/selectize-rendering-methods.html

Technically, under the hood, Shiny creates an JSON API for AJAX requests by calling shiny:::registerDataObj(). You can find an example of constructing your customized AJAX request here: http://shiny.rstudio.com/gallery/selectize-rendering-methods.html .

的例子,有光泽,稍后将反映在R code之间的另一个区别是,他们又怎么codeS表的内容成JSON的blob。 使用普通的对象每一行的例子EN codeS。例如,第一行是连接codeD为:

Another difference between the example and Shiny, which will later be reflected in the R code, is how they encodes the table content into a JSON blob. The example encodes each line using plain objects. For instance, the first row is encoded as:

{             名:虎尼克松,             位置:系统架构师,             工资:$三十二万零八百             START_DATE:2011 \ / 04 \ / 25,             写字楼:爱丁堡,             分机:5421 },

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

而闪亮的EN codeS中的每一行的 data.frame 阵列,例如,像

Whereas Shiny encodes each row of your data.frame as an array, e.g., something like,

[虎尼克松,系统架构师,  $ 320800,2011 \ / 04 \ / 25,爱丁堡,5421]

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

在差在 JSON数据会影响我们如何贯彻落实格式()功能后。

The difference in the raw JSON data affects how we would implement the format() function later.

最后,该示例使用一个固定的HTML &LT;表&gt; 模板来呈现的数据表。您可能已经注意到,唯一可见的列都包含在模板中(例如,分机号码列不在&LT;表&gt; 模板);而有光泽为您创建模板,你没有得到确定你的数据是如何绑定(如 {数据:名} )。执行

Finally, the example uses a fixed HTML <table> template to render the data table. You may have noticed that only visible columns are included in the template (for example, the Extension number column is not in the <table> template); whereas Shiny creates the template for you and you don't get to decide how your data binding (e.g. { "data": "name" },) is performed.

注意:在R code以下使用闪亮的开发分支,你可以在上面拉请求链接找到

虽然我们没有得到确定绑定到什么数据的列,我们可以选择通过指定 columnDefs 选项,当你调用隐藏的列的数据表()功能。您可以通过包装他们在一个列表 https://datatables.net/reference/option/ 定义的任何选项$ C> R中。

Although we don't get to decide which columns to bind to what data, we can choose which columns to hide by specifying the columnDefs options when you call the DataTable() function. You can pass whatever options that are defined in https://datatables.net/reference/option/ by wrapping them in a list in R.

的使用示例数据有光泽的应用程序的一个例子是:

An example of a Shiny app using your example data is:

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

没有什么特别的,除了这里,我已经改变了格式()相应的功能,因为正如前面提到的,闪亮的发送数据作为行数组,而不是对象。

There is nothing special here except that I've changed the format() function accordingly because, as mentioned before, Shiny sends data as row arrays instead of objects.

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)的数据表,你应该能够看到在扩展区域中显示的额外信息。

Now that if you click on the first (empty) column (because I've written no CSS) of your data table, you should be able to see the extra information shown in the expanded area.

上面的解决方案包括发送所有信息给客户端,虽然在大多数情况下使用,用户可能不打扰查看隐藏信息。从本质上讲,我们结束了发送大量冗余数据到客户端。

Above solution involves sending all information to the client, although in most use cases the user may not bother to view the hidden information. Essentially we end up with sending a lot of redundant data to the client side.

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

A better solution is to implement a AJAX request handler in Shiny, which only returns the information when needed (i.e. as the user requests).

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

To implement a AJAX request handler, one can use session$registerDataObj. This function registers a request handler at a unique URL, and returns this URL.

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

In order to call this registered request handler, you need to first send this AJAX URL to the client.

下面我砍死一个快速的解决方案:基本上你创建一个隐藏的&LT;输入&GT; 元素的网页上,您可以绑定一个变化事件侦听器。闪亮的服务器更新此&LT;输入&GT; 以通过函数调用将消息发送到客户端元素的值会议$ sendInputMessage 。一旦接收到消息,它改变了&LT的值;输入&GT; 元素,触发事件侦听器。然后,我们可以设置AJAX请求的URL正确

Below I hacked a quick solution: basically you create a hidden <input> element on the webpage on which you can bind a change event listener. The Shiny server updates this <input> element's value by sending a message to the client via the function call session$sendInputMessage. Once the message is received, it changes the value of the <input> element, triggering the event listener. We can then set up the AJAX request URL properly

之后,就可以启动任何正常的AJAX请求来获取你需要的数据。

Afterward, you can initiate any normal AJAX requests to fetch the data you need.

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

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

这篇关于闪亮的数据表与孩子用ajax行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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