Переместите функциональность javascript для кнопок во встроенные кнопки с возможностью DT. - PullRequest
0 голосов
/ 25 мая 2019

В связи с предыдущим вопросом, я застрял на том, как заставить функционировать JavaScript на встроенных кнопках в datatable. Я подозреваю, что это связано с инициированием javascript по сравнению с рендерингом кнопок, но до сих пор я не смог понять, как заставить функционировать работать со встроенными кнопками ..

В приложении ниже я дал встроенным кнопкам другое имя, но при тестировании без обычных кнопок действий в приложении и присвоению встроенным кнопкам того же имени javascript не реагирует, как кажется

предыдущий вопрос

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)

пс, чтобы прокомментировать о выборе: я полностью удалил css, за исключением курсивной части. Я имею в виду, что после нажатия «Отменить выбор» или «Восстановить», я хотел бы отменить выбор строк, по которым щелкнули, которые показаны на этом изображении синим цветом (цвет, который они получают при нажатии на них)

ОБНОВЛЕНИЕ вопроса

Я пытаюсь изменить столбец Selected для хранения значений T и F, и мне кажется, что мне удалось получить коды remove и `restore, работающие с этим, но я не уверен, как получить новую функцию рендеринга. То, что у меня есть, так это:

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"){', enter image description here

1 Ответ

1 голос
/ 25 мая 2019

Аргумент dt функции действия кнопки (function(e,dt,node,config)) - это API экземпляра DataTables для хоста DataTable: https://datatables.net/reference/option/buttons.buttons.action

В функции initComplete function(settings) этот объект является settings.oInstance.api(), который называется table в коде JS (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);});",
    "}"
  )
)    

EDIT

Вот полный код обновленного решения:

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


«Отменить выделение» с сервера блестящий: пример

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