1

How do I use Autofill extension on editable tables? In the example below, modified from this previous question , the autofill action (filling in table using the blue square) isn't being captured.

Thanks

Iain

library(shiny)
library(DT)
shinyApp(
ui = fluidPage(
DTOutput('x1'),
verbatimTextOutput("print")
),
server = function(input, output, session) {
x = reactiveValues(df = NULL)

observe({
  df <- iris
  df$Date = Sys.time() + seq_len(nrow(df))
  x$df <- df
})

output$x1 = renderDT(x$df, selection = 'none', editable = TRUE, extensions = 'AutoFill', options = list(autoFill = TRUE))

proxy = dataTableProxy('x1')

observeEvent(input$x1_cell_edit, {
  info = input$x1_cell_edit
  str(info)
  i = info$row
  j = info$col
  v = info$value

  x$df[i, j] <- isolate(DT::coerceValue(v, x$df[i, j]))
})

output$print <- renderPrint({
  x$df
})
}
)
Iain
  • 1,298
  • 3
  • 17
  • 26
  • There seem to be some issues with the datatable extensions in shiny, see here: https://rstudio.github.io/DT/extensions.html. Outside shiny your example works well. Workaround idea could be to capture the state of the app right after the change (since it does change indeed but very quickly reverts),...but capturing the changes is not possible to my knowledge,... – Tonio Liebrand Jan 18 '19 at 21:48
  • Thanks - I will raise as potential bug – Iain Jan 20 '19 at 01:28

1 Answers1

1

Here is a way. It requires server = FALSE.

library(shiny)
library(DT)

callback <- c(
  "var tbl = $(table.table().node());",
  "var id = tbl.closest('.datatables').attr('id');",
  "table.on('autoFill', function(e, datatable, cells){",
  "  var out = [];",
  "  for(var i=0; i<cells.length; ++i){",
  "    var cells_i = cells[i];",
  "    for(var j=0; j < cells_i.length; ++j){",
  "      var c = cells_i[j];",
  "      var value = c.set === null ? '' : c.set;", # null causes problem in R
  "      out.push({row: c.index.row+1, col: c.index.column, value: value});",
# if you want to color the autofilled cells, uncomment the the two lines below  
#  "      $(table.cell(c.index.row, c.index.column).node())",
#  "        .css('background-color', 'yellow');",
  "    }",
  "  }",
  "  Shiny.setInputValue(id + '_cells_filled:DT.cellInfo', out);",
  "  table.rows().invalidate();", # this updates the column type
  "});"
)

ui <- fluidPage(
  br(),
  DTOutput("dt"),
  br(),
  verbatimTextOutput("table")
)

server <- function(input, output){

  dat <- iris[1:5,]

  output[["dt"]] <- renderDT({
    datatable(dat, 
              editable = list(target = "cell"),
              selection = "none",
              extensions = "AutoFill",
              callback = JS(callback), 
              options = list(
                autoFill = TRUE
              )
    )
  }, server = FALSE)

  Data <- reactive({
    info <- rbind(input[["dt_cells_filled"]], input[["dt_cell_edit"]])
    if(!is.null(info)){
      info <- unique(info)
      info$value[info$value==""] <- NA
      dat <<- editData(dat, info)
    }
    dat
  })

  output[["table"]] <- renderPrint({Data()})  
}

shinyApp(ui, server)

enter image description here


EDIT

With server = TRUE it suffices to replace

dat <<- editData(dat, info)

with

dat <<- editData(dat, info, proxy = "dt")
Stéphane Laurent
  • 48,421
  • 14
  • 86
  • 170