使用DT数据表将按钮的JavaScript功能移动到嵌入式按钮

时间:2019-05-25 15:49:30

标签: javascript r shiny dt

与上一个问题有关,我被困在如何使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)

UPDATE2 包含修改和更正的工作答案。根据最后的评论看最后的润色

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对所选内容进行评论 除了斜体部分,我完全删除了CSS。我的意思是,单击取消选择或还原后,我想取消选择单击的行,此行以蓝色显示(此图像在您单击时显示的颜色) enter image description here

1 个答案:

答案 0 :(得分:0)

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

initComplete函数function(settings)中,该对象为settings.oInstance.api(),在JS代码(table)中被命名为var 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)

enter image description here