扩展和折叠Shiny DataTable中的子行 [英] Expanding and collapsing child rows in Shiny DataTable

查看:116
本文介绍了扩展和折叠Shiny DataTable中的子行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在Shiny中复制数据表对象.当前,我可以在Shiny环境之外运行代码的数据表部分时显示所需的内容.但是,当我运行整个代码时,它没有显示子表.

I'm having trouble replicating a datatable object in Shiny. Currently, I can display what I want when I run the data table portion of the code outside of a Shiny environment. However, when I run the entire code, it's not displaying the child table.

library(DT)
library(data.table)
library(shiny)

shinyApp(
 ui = fluidPage(DT::dataTableOutput('tbl')),
 server = function(input, output) {
 output$tbl = DT::renderDataTable(

  datatable({
    #Transform dataframe to data.table and turn the dataframe rowname into a data.table column called model
    mtcars_dt = data.table(mtcars)
    mtcars_dt[["model"]] = rownames(mtcars)
    setcolorder(mtcars_dt,c(
      which(colnames(mtcars_dt) %in% c("mpg","cyl","model")),
      which(!colnames(mtcars_dt) %in% c("mpg","cyl","model"))
    ))

    #Turn data table into a nested data.table by mpg, cyl
    mtcars_dt <- mtcars_dt[, list(cars=list(.SD)), by = list(mpg,cyl)]


    #configure datatable. Hide row number and cars columns [0,4] and enable details control on plus sign column[1]
    #turn rows into child rows and remove from parent
    cbind(' ' = '&oplus;', mtcars_dt)}, 

    escape = -2,
    options = list(
      columnDefs = list(
        list(visible = FALSE, targets = c(0,4)),
        list(orderable = FALSE, className = 'details-control', targets = 1)
      )
    ),
    callback = JS("
                  table.column(1).nodes().to$().css({cursor: 'pointer'});

                  // Format cars object into another table
                  var format = function(d) {
                  if(d != null){ 
                  var result = ('<table id=\"child_' + d[2] + '_' + d[3] + '\">').replace('.','_') + '<thead><tr>'
                  for (var col in d[4]){
                  result += '<th>' + col + '</th>'
                  }
                  result += '</tr></thead></table>'
                  return result
                  }else{
                  return '';
                  }
                  }

                  var format_datatable = function(d) {
                  var dataset = [];
                  for (i = 0; i < + d[4]['model'].length; i++) {
                  var datarow = [];
                  for (var col in d[4]){
                  datarow.push(d[4][col][i])
                  }
                  dataset.push(datarow)
                  }
                  var subtable = $(('table#child_' + d[2] + '_' + d[3]).replace('.','_')).DataTable({
                  'data': dataset,
                  'autoWidth': true, 
                  'deferRender': true, 
                  'info': false, 
                  'lengthChange': false, 
                  'ordering': true, 
                  'paging': false, 
                  'scrollX': false, 
                  'scrollY': false, 
                  'searching': false 
                  });
                  };

                  table.on('click', 'td.details-control', function() {
                  var td = $(this), row = table.row(td.closest('tr'));
                  if (row.child.isShown()) {
                  row.child.hide();
                  td.html('&oplus;');
                  } else {
                  row.child(format(row.data())).show();
                  td.html('&CircleMinus;');
                  format_datatable(row.data())
                  }
                  });")
      )
    )
  }
)

感谢您的帮助!

推荐答案

此处的关键似乎是对象与数组之间的区别.使用Shiny时,row.data()是一个数组,并且它的第五个元素也是一个数组(在这里,我单击了主表的第二行):

The key here seemed to be the difference between an object and an array. When using shiny, row.data() is an array and its fifth element is an array as well (here I clicked on the second row in the main table):

["2", "&oplus;", 22.8, 4, Array(2)]

在光亮的环境之外,row.data()看起来像这样:

Outside of the shiny environment, row.data() looks like this:

["2", "&oplus;", 22.8, 4, Object]

如您所见,第五个元素是一个对象!我不知道为什么会这样.我想幕后使用的库版本可能有所不同.

As you can see, the fifth element is an object! Why this is the case, I cannot tell. I guess there might be a difference in the versions of the libraries used behind the scenes.

要使其正常工作,我们需要进行2处更改:

To get this working we need to make 2 changes:

1.更改format():

1. Change format():

var format = function(d) {
  if(d != null) { 
    var result = ('<table id=\"child_' + d[2] + '_' + d[3] + '\">').replace('.','_') + '<thead><tr>'
    for (var col in d[4][0]) {
       result += '<th>' + col + '</th>'
    }
    result += '</tr></thead></table>'
    return result
  } else {
    return '';
  }
}

在这里,我们只是在第4行中添加了[0].如上所示,d[4]是一个数组.对于第二行数据,它由2个对象组成. (var col in d[4])将返回01(对象的索引),而(var col in d[4][0])将返回第一个对象的元素(即列名称).

Here we just added [0] in line 4. As shown above, d[4] is an array. In case of the second row of data it consists of 2 objects. (var col in d[4]) would return 0 and 1 (indices of the objects) whereas (var col in d[4][0]) returns the elements of the first object (so the column names).

2.更改format_datatable():

2. Change format_datatable():

var format_datatable = function(d) {
  var dataset = [];
  for (i = 0; i <=  d[4].length-1; i++) {
    var datarow = $.map(d[4][i], function(value, index) {
      return [value];
    });
    dataset.push(datarow);
  }
  //  ...
  //  the rest did not change
}

在这里,我们使用$.map()将表示为对象的每个汽车模型(因此,在d[4]中的每个元素)转换为数组.之后,我们只需将此数组添加到dataset.

Here we convert each car model (so each element in d[4]), which is represented as an object, into an array using $.map(). After that we just add this array to dataset.

创建子表的代码需要这些数组.数据表在数据类型方面的处理方式有所不同,可以在此处进行检查.

The code that creates the subtable expects these arrays. Data is handled differently by DataTables with respect to its type which can be checked here.

这篇关于扩展和折叠Shiny DataTable中的子行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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