具有父/子关系的闪亮可折叠数据表

Posted

技术标签:

【中文标题】具有父/子关系的闪亮可折叠数据表【英文标题】:Collapsible Datatable in Shiny with Parent/Child relation 【发布时间】:2020-05-28 13:20:35 【问题描述】:

我需要使用闪亮创建一个可折叠的数据表。该代码在本地运行但不在闪亮服务器上运行时有效。我收到一条错误消息,提示“DataTables 警告:表 id=DataTables_Table_0 - [<-.data.frame(*tmp*,,j,value = list(list(structure(list(: 替换元素 2 有 3 行,需要 10 行) 中的错误”

我目前使用的是 1.10.4-3 版本的 data.table 包

代码:

       colnames(selected_df_final) <- c('tcluster_id','TIME FIRST RCVD','ALERT NAME', 'NODE ID', 'DESCRIPTION', 'MANAGER CLASS')

      mtcars_dt = data.table(selected_df_final)
      setkey(mtcars_dt, tcluster_id)

      cyl_dt = unique(mtcars_dt[, list(tcluster_id)])
      setkey(cyl_dt, tcluster_id)

      mtcars_dt = 
        mtcars_dt[, list("_details" = list(purrr::transpose(.SD))), by = list(tcluster_id)]
      mtcars_dt[, ' ' := '&oplus;']

      cyl_dt = merge(cyl_dt, mtcars_dt, all.x = TRUE )
      setcolorder(cyl_dt, c(length(cyl_dt),c(1:(length(cyl_dt) - 1))))

      ## the callback
      ## the callback
      callback_js = JS(
        "table.column(1).nodes().to$().css(cursor: 'pointer');",
        "",
        "// make the table header of the nested table",
        "var format = function(d, childId)",
        "  if(d != null)",
        "    var html = ", 
        "      '<table class=\"display compact hover\" id=\"' + childId + '\"><thead><tr>';",
        "    for (var key in d[d.length-1][0]) ",
        "      html += '<th>' + key + '</th>';",
        "    ",
        "    html += '</tr></thead></table>'",
        "    return html;",
        "   else ",
        "    return '';",
        "  ",
        ";",
        "",
        "// row callback to style the rows of the child tables",
        "var rowCallback = function(row, dat, displayNum, index)",
        "  if($(row).hasClass('odd'))",
        "    $(row).css('background-color', 'papayawhip');",
        "    $(row).hover(function()",
        "      $(this).css('background-color', '#E6FF99');",
        "    , function() ",
        "      $(this).css('background-color', 'papayawhip');",
        "    );",
        "   else ",
        "    $(row).css('background-color', 'lemonchiffon');",
        "    $(row).hover(function()",
        "      $(this).css('background-color', '#DDFF75');",
        "    , function() ",
        "      $(this).css('background-color', 'lemonchiffon');",
        "    );",
        "  ",
        ";",
        "",
        "// header callback to style the header of the child tables",
        "var headerCallback = function(thead, data, start, end, display)",
        "  $('th', thead).css(",
        "    'border-top': '3px solid indigo',", 
        "    'color': 'indigo',",
        "    'background-color': '#fadadd'",
        "  );",
        ";",
        "",
        "// make the datatable",
        "var format_datatable = function(d, childId)",
        "  var dataset = [];",
        "  var n = d.length - 1;",
        "  for(var i = 0; i < d[n].length; i++)",
        "    var datarow = $.map(d[n][i], function (value, index) ",
        "      return [value];",
        "    );",
        "    dataset.push(datarow);",
        "  ",
        "  var id = 'table#' + childId;",
        "  if (Object.keys(d[n][0]).indexOf('_details') === -1) ",
        "    var subtable = $(id).DataTable(",
        "                 'data': dataset,",
        "                 'autoWidth': true,",
        "                 'deferRender': true,",
        "                 'info': false,",
        "                 'lengthChange': false,",
        "                 'ordering': d[n].length > 1,",
        "                 'order': [],",
        "                 'paging': false,",
        "                 'scrollX': false,",
        "                 'scrollY': false,",
        "                 'searching': false,",
        "                 'sortClasses': false,",
        "                 'rowCallback': rowCallback,",
        "                 'headerCallback': headerCallback,",
        "                 'columnDefs': [targets: '_all', className: 'dt-center']",
        "               );",
        "   else ",
        "    var subtable = $(id).DataTable(",
        "            'data': dataset,",
        "            'autoWidth': true,",
        "            'deferRender': true,",
        "            'info': false,",
        "            'lengthChange': false,",
        "            'ordering': d[n].length > 1,",
        "            'order': [],",
        "            'paging': false,",
        "            'scrollX': false,",
        "            'scrollY': false,",
        "            'searching': false,",
        "            'sortClasses': false,",
        "            'rowCallback': rowCallback,",
        "            'headerCallback': headerCallback,",
        "            'columnDefs': [", 
        "              targets: -1, visible: false,", 
        "              targets: 0, orderable: false, className: 'details-control',", 
        "              targets: '_all', className: 'dt-center'",
        "             ]",
        "          ).column(0).nodes().to$().css(cursor: 'pointer');",
        "  ",
        ";",
        "",
        "// display the child table on click",
        "table.on('click', 'td.details-control', function()",
        "  var tbl = $(this).closest('table'),",
        "      tblId = tbl.attr('id'),",
        "      td = $(this),",
        "      row = $(tbl).DataTable().row(td.closest('tr')),",
        "      rowIdx = row.index();",
        "  if(row.child.isShown())",
        "    row.child.hide();",
        "    td.html('&oplus;');",
        "   else ",
        "    var childId = tblId + '-child-' + rowIdx;",
        "    row.child(format(row.data(), childId)).show();",
        "    td.html('&CircleMinus;');",
        "    format_datatable(row.data(), childId);",
        "  ",
        ");")

      ## datatable
      datatable(cyl_dt, callback = callback_js, escape = -2,
                options = list(
                  columnDefs = list(
                    list(visible = FALSE, targets = ncol(cyl_dt)),
                    list(orderable = FALSE, className = 'details-control', targets = 1),
                    list(className = "dt-center", targets = "_all")
                  )
                ))

【问题讨论】:

您的代码不可复现,请提供selected_df_final。此外,您的帖子中没有闪亮的代码。请提供重现问题的最小示例。 感谢@Stéphane Laurent 的评论。我能够生成闪亮服务器代码并使其与 mtcars 数据一起使用。造成问题的原因是 SERVER=FALSE 代码 【参考方案1】:

我能够让它工作。下面是相同的闪亮服务器代码。使它工作的代码是添加 SERVER = FALSE。

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

ui <- fluidPage(fluidRow(DT::dataTableOutput(width = "100%", "table")))

server <- function(input, output) 

  output$table = DT::renderDataTable(

    mtcars_dt = data.table(mtcars)
    setkey(mtcars_dt, cyl)

    cyl_dt = unique(mtcars_dt[, list(cyl)])
    setkey(cyl_dt, cyl)

    mtcars_dt = 
      mtcars_dt[, list("_details" = list(purrr::transpose(.SD))), by = list(cyl)]
    mtcars_dt[, ' ' := '&oplus;']

    cyl_dt = merge(cyl_dt, mtcars_dt, all.x = TRUE )
    setcolorder(cyl_dt, c(length(cyl_dt),c(1:(length(cyl_dt) - 1))))

    ## the callback
    callback = JS(
      "table.column(1).nodes().to$().css(cursor: 'pointer');",
      "",
      "// make the table header of the nested table",
      "var format = function(d, childId)",
      "  if(d != null)",
      "    var html = ",
      "      '<table class=\"display compact hover\" id=\"' + childId + '\"><thead><tr>';",
      "    for (var key in d[d.length-1][0]) ",
      "      html += '<th>' + key + '</th>';",
      "    ",
      "    html += '</tr></thead></table>'",
      "    return html;",
      "   else ",
      "    return '';",
      "  ",
      ";",
      "",
      "// row callback to style the rows of the child tables",
      "var rowCallback = function(row, dat, displayNum, index)",
      "  if($(row).hasClass('odd'))",
      "    $(row).css('background-color', 'papayawhip');",
      "    $(row).hover(function()",
      "      $(this).css('background-color', '#E6FF99');",
      "    , function() ",
      "      $(this).css('background-color', 'papayawhip');",
      "    );",
      "   else ",
      "    $(row).css('background-color', 'lemonchiffon');",
      "    $(row).hover(function()",
      "      $(this).css('background-color', '#DDFF75');",
      "    , function() ",
      "      $(this).css('background-color', 'lemonchiffon');",
      "    );",
      "  ",
      ";",
      "",
      "// header callback to style the header of the child tables",
      "var headerCallback = function(thead, data, start, end, display)",
      "  $('th', thead).css(",
      "    'border-top': '3px solid indigo',",
      "    'color': 'indigo',",
      "    'background-color': '#fadadd'",
      "  );",
      ";",
      "",
      "// make the datatable",
      "var format_datatable = function(d, childId)",
      "  var dataset = [];",
      "  var n = d.length - 1;",
      "  for(var i = 0; i < d[n].length; i++)",
      "    var datarow = $.map(d[n][i], function (value, index) ",
      "      return [value];",
      "    );",
      "    dataset.push(datarow);",
      "  ",
      "  var id = 'table#' + childId;",
      "  if (Object.keys(d[n][0]).indexOf('_details') === -1) ",
      "    var subtable = $(id).DataTable(",
      "                 'data': dataset,",
      "                 'autoWidth': true,",
      "                 'deferRender': true,",
      "                 'info': false,",
      "                 'lengthChange': false,",
      "                 'ordering': d[n].length > 1,",
      "                 'order': [],",
      "                 'paging': false,",
      "                 'scrollX': false,",
      "                 'scrollY': false,",
      "                 'searching': false,",
      "                 'sortClasses': false,",
      "                 'rowCallback': rowCallback,",
      "                 'headerCallback': headerCallback,",
      "                 'columnDefs': [targets: '_all', className: 'dt-center']",
      "               );",
      "   else ",
      "    var subtable = $(id).DataTable(",
      "            'data': dataset,",
      "            'autoWidth': true,",
      "            'deferRender': true,",
      "            'info': false,",
      "            'lengthChange': false,",
      "            'ordering': d[n].length > 1,",
      "            'order': [],",
      "            'paging': false,",
      "            'scrollX': false,",
      "            'scrollY': false,",
      "            'searching': false,",
      "            'sortClasses': false,",
      "            'rowCallback': rowCallback,",
      "            'headerCallback': headerCallback,",
      "            'columnDefs': [",
      "              targets: -1, visible: false,",
      "              targets: 0, orderable: false, className: 'details-control',",
      "              targets: '_all', className: 'dt-center'",
      "             ]",
      "          ).column(0).nodes().to$().css(cursor: 'pointer');",
      "  ",
      ";",
      "",
      "// display the child table on click",
      "table.on('click', 'td.details-control', function()",
      "  var tbl = $(this).closest('table'),",
      "      tblId = tbl.attr('id'),",
      "      td = $(this),",
      "      row = $(tbl).DataTable().row(td.closest('tr')),",
      "      rowIdx = row.index();",
      "  if(row.child.isShown())",
      "    row.child.hide();",
      "    td.html('&oplus;');",
      "   else ",
      "    var childId = tblId + '-child-' + rowIdx;",
      "    row.child(format(row.data(), childId)).show();",
      "    td.html('&CircleMinus;');",
      "    format_datatable(row.data(), childId);",
      "  ",
      ");")

    ## datatable
    datatable(cyl_dt, callback = callback, escape = -2,
              options = list(
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(cyl_dt)),
                  list(orderable = FALSE, className = 'details-control', targets = 1),
                  list(className = "dt-center", targets = "_all")
                )
              ))
,server = FALSE)


shinyApp (ui = ui, server = server)

【讨论】:

以上是关于具有父/子关系的闪亮可折叠数据表的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap 4嵌套折叠“数据父级”不起作用

R闪亮包中的父/子行

如何以编程方式折叠闪亮仪表板中的框

数据结构之树

获取核心数据中一对多关系的计数

从核心数据获取请求中排除反向关系