【问题标题】:Move javascript functionality of buttons to embedded buttons with DT datatable将按钮的 javascript 功能移动到带有 DT 数据表的嵌入式按钮
【发布时间】:2019-05-25 15:49:30
【问题描述】:

与上一个问题有关,我被困在如何让 javascript 功能在数据表中的嵌入式按钮上运行。 我怀疑这与 javascript 的启动与按钮的呈现有关,但到目前为止,我还没有弄清楚如何使功能与嵌入式按钮一起工作..

在下面的应用程序中,我给嵌入的按钮起了一个不同的名称,但是在没有应用程序中的常规操作按钮的情况下对其进行测试,并且给嵌入的按钮赋予相同的名称,javascript 似乎没有反应

previous question

library(shiny)
library(DT)

initComplete <- c(
  "function(settings) {",
  "  var table = settings.oInstance.api();", 
  "  var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'",
  "  var checkmark = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-ok\"></i></span>'",
  "  $('#SubmitRemoval').on('click', function(){",
  "    table.$('tr.selected').addClass('x');",
  "    table.$('tr.selected')",
  "      .each(function(){$(this).find('td').eq(1).html(cross);});",
  "    var excludedRows = [];",
  "    table.$('tr').each(function(i, row){",
  "      if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
  "    });",
  "    Shiny.setInputValue('excludedRows', excludedRows);",
  "  });",
  "  $('#UndoRemoval').on('click', function(){",
  "    table.$('tr').removeClass('x');",
  "    table.$('tr')",
  "      .each(function(i){$(this).find('td').eq(1).html(checkmark);});",
  "    Shiny.setInputValue('excludedRows', null);",
  "  });",
  "}"
)

callback <- "
var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'
var xrows = [];
table.on('preDraw', function(e, settings) {
  var tbl = settings.oInstance.api();
  var nrows = tbl.rows().count();
  var rows = tbl.$('tr');
  var some = false; var r = 0;
  while(!some && r<nrows){
    if($(rows[r]).hasClass('x')){
      some = true
    }
    r++;
  }
  if(some){
    xrows = [];
    for(var i = 0; i < nrows; i++){
      if($(rows[i]).hasClass('x')){
        xrows.push(rows[i].getAttribute('id'));
      }
    }
  }
}).on('draw.dt', function(){
  for(var i=0; i<xrows.length; i++){
    var row = $('#' + xrows[i]);
    row.addClass('x').find('td').eq(1).html(cross);
  }
  xrows = [];
});
"

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".x { background-color: rgb(211,211,211) !important; font-style: italic}
       table.dataTable tr.selected.x td { background-color: rgb(211,211,211) !important;}"
    ))
  ),
  actionButton('SubmitRemoval', 'Exclude selected rows'),
  actionButton('UndoRemoval', 'Include full data'),
  br(),
  DTOutput('mytable')

)

server <- function(input, output,session) {

  dat <- cbind(Selected = '<span style="color:red; font-size:18px"><i class="glyphicon glyphicon-ok"></i></span>', 
               mtcars[1:6,], id = 1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              escape = -2, 
              callback = JS(callback),
              extensions = c('Buttons', 'Scroller'),

              options = list(
                initComplete = JS(initComplete),
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all")
                ), 
                dom = 'frtipB',

                buttons = list('copy', 'csv',
                               list(
                                 extend = "collection",
                                 text = 'Deselect', 
                                 action = DT::JS("function ( e, dt, node, config ) {
                                       Shiny.setInputValue('SubmitRemovalEmb', true, {priority: 'event'});
                                     }")
                               ),
                               list(
                                 extend = "collection",
                                 text = 'Restore', 
                                 action = DT::JS("function ( e, dt, node, config ) {
                                       Shiny.setInputValue('UndoRemovalEmb', true, {priority: 'event'});
                                     }")
                               )
                )

              )
    )
  })

  proxy <- dataTableProxy("mytable")

  observeEvent(input[["UndoRemoval"]], { 
    proxy %>% selectRows(NULL)
  })

}

shinyApp(ui, server)

更新2 包括修改和更正的工作答案。根据最后的评论查看最后的收尾工作

library(shiny)
library(DT)


callback <- "
var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'
var xrows = [];
table.on('preDraw', function(e, settings) {
  var tbl = settings.oInstance.api();
  var nrows = tbl.rows().count();
  var rows = tbl.$('tr');
  var some = false; var r = 0;
  while(!some && r<nrows){
    if($(rows[r]).hasClass('x')){
      some = true
    }
    r++;
  }
  if(some){
    xrows = [];
    for(var i = 0; i < nrows; i++){
      if($(rows[i]).hasClass('x')){
        xrows.push(rows[i].getAttribute('id'));
      }
    }
  }
}).on('draw.dt', function(){
  for(var i=0; i<xrows.length; i++){
    var row = $('#' + xrows[i]);
    row.addClass('x').find('td').eq(1).html(cross);
  }
  xrows = [];
});
"

ui <- fluidPage(
  tags$head(
    tags$style(HTML(
      ".x { font-style: italic}"
    ))
  ),

  br(),
  DTOutput('mytable')

)

server <- function(input, output,session) {

  dat <- cbind(Selected = '<span style="color:red; font-size:18px"><i class="glyphicon glyphicon-ok"></i></span>', 
               mtcars[1:6,], id = 1:6)

  output[["mytable"]] <- renderDT({
    datatable(dat, 
              escape = -2, 
              callback = JS(callback),
              extensions = c('Buttons', 'Scroller'),
              options = list(
                rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                columnDefs = list(
                  list(visible = FALSE, targets = ncol(dat)),
                  list(className = "dt-center", targets = "_all")
                ), 
                dom = 'B',
                buttons = list('copy', 'csv',
                               list(
                                 extend = "collection",
                                 text = 'Deselect', 
                                 action = DT::JS(
                                   c(
                                     "function ( e, table, node, config ) {",
                                     "  var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'",
                                     "  table.$('tr.selected').addClass('x');",
                                     "  table.$('tr.selected')",
                                     "    .each(function(){$(this).find('td').eq(1).html(cross);}).removeClass('selected');",
                                     "    var excludedRows = [];",
                                     "    table.$('tr').each(function(i, row){",
                                     "      if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
                                     "    });",
                                     "    Shiny.setInputValue('excludedRows', excludedRows);",
                                     "}"
                                   )
                                 )   
                               ),
                               list(
                                 extend = "collection",
                                 text = 'Restore', 
                                 action = DT::JS(
                                   c(
                                     "function ( e, table, node, config ) {",
                                     "  var checkmark = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-ok\"></i></span>'",
                                     "    table.$('tr')",
                                     "      .each(function(i){$(this).find('td').eq(1).html(checkmark);});",
                                     "    table.$('tr').removeClass('x').removeClass('selected');",
                                     "    Shiny.setInputValue('excludedRows', null);",
                                     " }"
                                   )
                                 )
                               )

                )
              )
    )
  })

  proxy <- dataTableProxy("mytable")



  observeEvent(input[['excludedRows']], { 
    print(input[['excludedRows']])}, ignoreInit =  T)


}

shinyApp(ui, server)

ps 对 select 发表评论: 我完全删除了 CSS,除了斜体部分。我的意思是,在单击取消选择或恢复后,我想取消选择单击的行,在此图中以蓝色显示(单击它们时它们得到的颜色)

更新问题

我正在尝试将Selected 列更改为保存TFvalues,我想我设法让remove 和`恢复代码使用它,但我不知道如何让新的渲染功能工作。我到目前为止是这样的:

render <- c(
  'function(data, type, row, meta){',
  '  if(type === "display"){',
  '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-remove\\\"></i></span>";',
  '  } else {',
  '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-ok\\\"></i></span>";',
  '  }',
  '}'
)

问题是我不知道如何更改明显不正确的 IF 语句:' if(type === "display"){',

【问题讨论】:

    标签: javascript r shiny dt


    【解决方案1】:

    按钮动作函数(function(e,dt,node,config))的参数dt是宿主DataTable的DataTables实例API:https://datatables.net/reference/option/buttons.buttons.action

    initComplete函数function(settings)中,这个对象是settings.oInstance.api(),在JS代码中命名为tablevar table = settings.oInstance.api();)。

    所以将function(e,dt,node,config)替换为function(e,table,node,config),并将JS代码移至按钮动作函数体:

    action = DT::JS(
      c(
        "function ( e, table, node, config ) {",
        "  var cross = '<span style=\"color:red; font-size:18px\"><i class=\"glyphicon glyphicon-remove\"></i></span>'",
        "  table.$('tr.selected').addClass('x');",
        "  table.$('tr.selected')",
        "    .each(function(){$(this).find('td').eq(1).html(cross);});",
        "}"
      )
    )    
    

    编辑

    以下是更新解决方案的完整代码:

    library(shiny)
    library(DT)
    
    removal <- c(
      "function(e, table, node, config) {",
      "  table.$('tr.selected').addClass('x').each(function(){",
      "    var td = $(this).find('td').eq(1)[0];", 
      "    var cell = table.cell(td);", 
      "    cell.data('remove');",
      "  });",
      "  table.rows().deselect();",
      "  var excludedRows = [];",
      "  table.$('tr').each(function(i, row){",
      "    if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
      "  });",
      "  Shiny.setInputValue('excludedRows', excludedRows);",
      "}"
    )
    
    restore <- c(
      "function(e, table, node, config) {",
      "  table.$('tr').removeClass('x').each(function(){",
      "    var td = $(this).find('td').eq(1)[0];", 
      "    var cell = table.cell(td);", 
      "    cell.data('ok');",
      "  });",
      "  Shiny.setInputValue('excludedRows', null);",
      "}"
    )
    
    render <- c(
      'function(data, type, row, meta){',
      '  if(type === "display"){',
      '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-" + data + "\\\"></i></span>";',
      '  } else {',
      '    return data;',
      '  }',
      '}'
    )
    
    ui <- fluidPage(
      tags$head(
        tags$style(HTML(
          ".x { color: rgb(211,211,211); font-style: italic; }"
        ))
      ),
      fluidRow(
        column(
          6, 
          tags$label("Excluded rows"),
          verbatimTextOutput("excludedRows")
        ),
        column(
          6, 
          tags$label("Included rows"),
          verbatimTextOutput("includedRows")
        )
      ),
      br(),
      DTOutput('mytable')
    )
    
    server <- function(input, output,session) {
    
      dat <- cbind(Selected = "ok", mtcars[1:6,], id = 1:6)
    
      output[["mytable"]] <- renderDT({
        datatable(dat, 
                  extensions = c("Select", "Buttons"),
                  options = list(
                    rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                    columnDefs = list(
                      list(visible = FALSE, targets = ncol(dat)),
                      list(className = "dt-center", targets = "_all"),
                      list(targets = 1, render = JS(render)) 
                    ),
                    dom = "B",
                    buttons = list("copy", "csv",
                                   list(
                                     extend = "collection",
                                     text = 'Deselect', 
                                     action = JS(removal)
                                   ),
                                   list(
                                     extend = "collection",
                                     text = 'Restore', 
                                     action = JS(restore)
                                   )
                    )
                  )
        )
      }, server = FALSE)
    
        output$excludedRows <- renderPrint({
          input[["excludedRows"]]
        })
    
        output$includedRows <- renderPrint({
          setdiff(1:nrow(dat), input[["excludedRows"]])
        })
    
    }
    
    shinyApp(ui, server)
    


    从闪亮的服务器中“取消选择”:示例

    library(shiny)
    library(DT)
    library(shinyjs)
    
    js <- paste(
      "var table = $('#mytable').find('table').DataTable();",
      "var rowsindices = [%s];",
      "for(var i=0; i<rowsindices.length; ++i){",
      "  var idx = rowsindices[i];",
      "  table.cell(idx, 1).data('remove');",
      "  table.row(idx).select();",
      "}",
      "$('.dt-button.buttons-collection').eq(0).click();", 
      sep = "\n"
    )
    
    removal <- c(
      "function(e, table, node, config) {",
      "  table.$('tr.selected').addClass('x').each(function(){",
      "    var td = $(this).find('td').eq(1)[0];", 
      "    var cell = table.cell(td);", 
      "    cell.data('remove');",
      "  });",
      "  table.rows().deselect();",
      "  var excludedRows = [];",
      "  table.$('tr').each(function(i, row){",
      "    if($(this).hasClass('x')){excludedRows.push(parseInt($(row).attr('id')));}",
      "  });",
      "    Shiny.setInputValue('excludedRows', excludedRows);",
      "}"
    )
    
    restore <- c(
      "function(e, table, node, config) {",
      "  table.$('tr').removeClass('x').each(function(){",
      "    var td = $(this).find('td').eq(1)[0];", 
      "    var cell = table.cell(td);", 
      "    cell.data('ok');",
      "  });",
      "  Shiny.setInputValue('excludedRows', null);",
      "}"
    )
    
    render <- c(
      'function(data, type, row, meta){',
      '  if(type === "display"){',
      '    return "<span style=\\\"color:red; font-size:18px\\\"><i class=\\\"glyphicon glyphicon-" + data + "\\\"></i></span>";',
      '  } else {',
      '    return data;',
      '  }',
      '}'
    )
    
    ui <- fluidPage(
      useShinyjs(),
      tags$head(
        tags$style(HTML(
          ".x { color: rgb(211,211,211); font-style: italic; }"
        ))
      ),
      fluidRow(
        column(
          6, 
          tags$label("Excluded rows"),
          verbatimTextOutput("excludedRows")
        ),
        column(
          6, 
          tags$label("Included rows"),
          verbatimTextOutput("includedRows")
        )
      ),
      br(), 
      actionButton("go", "Deselect rows 1, 2, 3"),
      br(),
      DTOutput('mytable')
    )
    
    server <- function(input, output,session) {
    
      dat <- cbind(Selected = "ok", mtcars[1:6,], id = 1:6)
    
      output[["mytable"]] <- renderDT({
        datatable(dat, 
                  extensions = c("Select", "Buttons"),
                  options = list(
                    rowId = JS(sprintf("function(data){return data[%d];}", ncol(dat))), 
                    columnDefs = list(
                      list(visible = FALSE, targets = ncol(dat)),
                      list(className = "dt-center", targets = "_all"),
                      list(targets = 1, render = JS(render)) 
                    ),
                    dom = "B",
                    buttons = list("copy", "csv",
                                   list(
                                     extend = "collection",
                                     text = 'Deselect', 
                                     action = JS(removal)
                                   ),
                                   list(
                                     extend = "collection",
                                     text = 'Restore', 
                                     action = JS(restore)
                                   )
                    )
                  )
        )
      }, server = FALSE)
    
      output$excludedRows <- renderPrint({
        input[["excludedRows"]]
      })
    
      output$includedRows <- renderPrint({
        setdiff(1:nrow(dat), input[["excludedRows"]])
      })
    
      observeEvent(input[["go"]], {
        rows <- c(1,2,3) - 1
        runjs(sprintf(js, paste0(rows, collapse=",")))
      })
    
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • @Mark 几个问题... 1) 在callback 中,您不必将table 替换为dt。 2) datatable 中缺少参数callback = JS(callback)。 3)删除选项initComplete,不再有initComplete。 4)您的代码中缺少括号。 5)在Restore按钮中,你还没有定义checkmark
    • @Mark Ah 好吧,你不想设置背景颜色。然后添加这个 CSS:table.dataTable tr.selected.x td { background-color: #ffffff !important;}.
    • @Mark 突出显示不过是背景颜色。我会尝试用.each(function(){$(this).find('td').eq(1).html(cross);}).removeClass('selected'); 替换.each(function(){$(this).find('td').eq(1).html(cross);});
    • @Mark 在我的渲染函数中,在if(type === "display"){ 之后,执行var x = data == true ? 'ok' : 'remove';。然后在后面的行中,将+ data + 替换为+ x +
    • @Mark 查看我的更新(“从闪亮的服务器中取消选择”)。您将要排除的行的索引放在向量x 中,然后运行runjs(sprintf(js, paste0(x-1, collapse=",")))。 JS 代码将单元格内容更改为“删除”,选择行,并触发单击“取消选择”按钮。
    猜你喜欢
    • 2015-03-07
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2022-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多