2

When using editable DataTable (package DT) where input is chosen by SelectInput the edits made isn't saved where it should be.

Choosing a specific variable shows for example rows 50-60 from datatable in first rows. Editing them saves the edits on the first rows instead of in rows 50-60.

In example below you can choose variable versicolor and delete setosa. Then edit Petal.Length to random number. Edit should be saved in row 51 but instead it is saved in row 1.

I am thinking about a workaround based on an index-column so the edits are saved in row number (indexrow). But I am not sure how to do that.

#Packages
library(shiny)
library(shinyalert)
library(shinydashboard)
library(leaflet)
library(leaflet.extras)
library(DT)

#data
iris = iris

#Shiny-app (ui)
header = dashboardHeader(title = "SelectInput DataTable example")

sidebar = dashboardSidebar(selectInput("species", "Choose species:  ",    choices = iris$Species, selected = "setosa",  multiple = TRUE))

body = dashboardBody(fluidRow(dataTableOutput("table")))

ui = dashboardPage(skin = "red", header, sidebar, body)

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


  output$table = DT::renderDataTable(iris[iris$Species %in% input$species,], editable = TRUE)

  proxy = dataTableProxy('table')

  observeEvent(input$table_cell_edit, {
    info = input$table_cell_edit
    str(info)
    i = info$row
    j = info$col
    v = info$value
    iris[i, j] <<- DT::coerceValue(v, iris[i, j])
    replaceData(proxy, iris, resetPaging = FALSE)  # important
  })
}

shinyApp(ui = ui, server = server)

1 Answers1

2

Try this:

#Packages
library(shiny)
library(shinydashboard)
library(DT)

#data
iris = iris

#Shiny-app (ui)
header = dashboardHeader(title = "SelectInput DataTable example")

sidebar = dashboardSidebar(selectInput("species", "Choose species: ", 
                                       choices = iris$Species, selected = "setosa",  multiple = TRUE))

body = dashboardBody(fluidRow(DT::dataTableOutput("table")))

ui = dashboardPage(skin = "red", header, sidebar, body)

# Javascript 
js <- function(rows){
  c(
    "function(settings){",
    "  var table = settings.oInstance.api();",
    sprintf("  var indices = [%s];", paste0(rows-1, collapse = ",")),
    "  table.rows(indices).remove().draw();",
    "}"
  )
}

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

  dat <- reactiveVal(iris)

  Rows <- reactive({
    which(iris$Species %in% input$species)
  })

  output$table = DT::renderDataTable({
    rows <- setdiff(1:nrow(iris), Rows())
    datatable(
      dat(), 
      editable = TRUE,
      options = list(
        initComplete = JS(js(rows))
      )
    )
  }, server = FALSE)

  observeEvent(input$table_cell_edit, {
    info = input$table_cell_edit
    info$row = Rows()[info$row+1] - 1
    dat(editData(dat(), info))
  })
}

shinyApp(ui = ui, server = server)
Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • Hi Stéphane. Your example with iris dataset works flawlessly! But when I adjust it to my own dataset it doesn't work properly. The edits isn't saved as where it should be. – Rprogrammer Jul 18 '19 at 08:15
  • @Rprogrammer Yes, sorry, I think I see why. It works for iris because the species are grouped in consecutive rows. Your problem is difficult, because the datatable is rerenderd when one changes input$species. I will try to think again about it, but I'm not sure to achieve. – Stéphane Laurent Jul 18 '19 at 08:17
  • When editing cell first time it doesn't save but editing same cell twice does work. – Rprogrammer Jul 18 '19 at 09:37
  • @Rprogrammer Strange, that works for me. Let me retry. – Stéphane Laurent Jul 18 '19 at 09:52
  • @Rprogrammer I confirm that works fine for me. Have you changed something as compared to the app you posted ? – Stéphane Laurent Jul 18 '19 at 09:56
  • It works well, sometimes twice sometimes once. Don't know why. I just replaced iris$species with my own dataset. Thank you Stephane – Rprogrammer Jul 22 '19 at 09:29