1

I made my code with dataTableproxy. Goal of my code is to open a pop up when I click the edit button. I can modify the line in the popup. The code is well done, i.e. when I edit a line I can modify it. Now I would like to save the values in the table I edited. I tried with coerceValue but it doesn't work. I think I didn't understand how to return the values from the proxy to the table I edited. Do you have an idea or some advice? Thanks in advance

# Global.R
  rm(list = ls())
  library(DT)
  library(shiny)
  library(shinydashboard)
  library(dplyr)
  library(lubridate)


  df<-data.frame(
    ECR= c("040/19", "050/20"),
    BEM=as.Date(c("2020/03/01", "2020/02/01")),
    BEE=c("", ""),
    FIN=c(4,-5)
    )

    #ui.R 
     ui<-fluidPage(
                 DT::dataTableOutput(outputId ="data.tab"),
                 actionButton(inputId = "edit",label = "Edit",color="green",class="butt4")
        )
    # Server.R
     server<-function(input, output,session) {

          mod_df <- shiny::reactiveValues(x = df)
          
          output$data.tab <- DT::renderDataTable({
                            DT=df
                            datatable(DT,selection = 'single',
                            escape=F,rownames = FALSE) 
          })
            
          observeEvent(input$edit,
                       {
                         showModal(modalDialog(
                                   infoBox("ECR CARD", uiOutput("card"), 
                                           icon = icon("line-chart")),
                                   DT::dataTableOutput('tab'),
                                   actionButton("save","Save changes")
                         ))
                         }
                       )
          
          output$tab <- DT::renderDT({
                            selected_row=input$data.tab_rows_selected
                            mod_df<-mod_df$x[selected_row,]
                            isolate(mod_df)
                            #print(mod_df)
                            }, escape=FALSE,selection = 'none',editable="all",rownames=FALSE
                            )
          
          val<-eventReactive(input$edit,{
                        selected_row=input$data.tab_rows_selected
                        mod_df<-mod_df$x[selected_row,]
                        mod_df
          })
          
          output$card<- renderText({
                        val.ecr<-val()
                        prettyNum(paste0(val.ecr[1,1]))
          }) 
          
          proxy <- DT::dataTableProxy('tab')
          
          shiny::observe({DT::replaceData(proxy, mod_df$x)})
          
          #######save - IT'S HERE I DON'T HOW I CAN DO?
          observeEvent(input$save,{
            
                          })

     }
    shinyApp(ui, server)
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
Sylvain
  • 43
  • 8
  • Perhaps answer [here](https://stackoverflow.com/questions/64997096/editable-calculation-with-dt-table-in-shiny) might be helpful – YBS Nov 28 '20 at 13:14
  • I've checked your link and I tried to reproduce the same thing but it doesn't work. I think I didn't understand the way to use dataTableproxy. – Sylvain Dec 01 '20 at 18:11
  • Just got the message. In the future, you can start the comment with @YBS, and then I will get the message. Let me take a look. – YBS Dec 01 '20 at 18:18
  • @YBS.OK! thanks in advance to your help. – Sylvain Dec 01 '20 at 18:33
  • Sorry, I have not been able to save the changes as it happening within the modal dialog and it needs to be closed to change the values in the table. – YBS Dec 02 '20 at 20:47
  • @YBS if I do understand you are able to change the value in initial table when you close modal dialog that's perfect, how do you it? – Sylvain Dec 03 '20 at 06:32
  • @YBS thanks to your help! I will check in my side. I ask me if it's really possible to do that? – Sylvain Dec 03 '20 at 18:50

2 Answers2

0

Thanks for the link. I added the observeEvent like that :

observeEvent(input$tab_cell_edit,
                        {
                          newval=input$tab_cell_edit
                          str(newval)
                          i=newval$row
                          j=newval$col
                          v=newval$value
                          mod_df$x[i,j] <<- (DT::coerceValue(v,mod_df$x[i,j]))
                          replaceData(proxy, mod_df$x,resetPaging = FALSE)
                         
                        })

and it doesn't work. I don't know how I can do that!

Sylvain
  • 43
  • 8
0

Here is the progress so far. I have created row_id column to merge the changes back to the initial data frame, and it is not displayed in the dialog box. I have used a new modalActionButton - thanks to @TimTeaFan, as your save button was not saving or closing the dialog box.

Sorry, I could not complete it. I have to complete some of my own work.

df<-data.frame(
  ECR= c("040/19", "050/20"),
  BEM=as.Date(c("2020/03/01", "2020/02/01")),
  BEE=c("", ""),
  FIN=c(4,-5)
)

# this is basically copied from actionButton() and just "`data-dismiss` = "modal"
# from modalButton() is added:
modalActionButton <- function(inputId, label, icon = NULL, width = NULL, ...) {

  value <- restoreInput(id = inputId, default = NULL)
  tags$button(id = inputId, type = "button", style = if (!is.null(width))
    paste0("width: ", validateCssUnit(width), ";"), type = "button",
    class = "btn btn-default action-button", `data-dismiss` = "modal", `data-val` = value,
    list(shiny:::validateIcon(icon), label), ...)

}

#ui.R
ui<-fluidPage(
  DT::dataTableOutput(outputId ="data.tab"),
  actionButton(inputId = "edit",label = "Edit",color="green"), # ,class="butt4"
  verbatimTextOutput("card"),
  DTOutput("tb1")
)
# Server.R
server<-function(input, output,session) {
  nrow <- nrow(df)
  row_id <- c(1:nrow)
  df1 <- data.frame(row_id,df)
  mod_df <- shiny::reactiveValues(x = df1)
  mod_row <- shiny::reactiveValues(dt=NULL)
  values = reactiveValues(modal_closed=F,
                          dat=NULL)

  output$data.tab <- DT::renderDataTable({
    #DT=mod_df$x
    datatable(isolate(mod_df$x),selection = 'single',
              escape=F,rownames = FALSE)
  })

  observeEvent(input$edit,
               {
                 values$modal_closed <- F
                 showModal(modalDialog(
                   infoBox("ECR CARD", uiOutput("card"),
                           icon = icon("line-chart")),
                   DT::dataTableOutput('tab'),
                   easyClose = FALSE,
                   # actionButton("save","Save")
                   # here is the modalActionButton
                   footer = modalActionButton("save", "Close")
                 ))
               }
  )

  val<-eventReactive(input$edit,{
    selected_row=input$data.tab_rows_selected
    data <- mod_df$x[selected_row,]
    data
  })

  observe({ mod_row$dt <- data.frame(req(val()))
            values$dat <- req(val())})

  output$card<- renderText({
    val.ecr<-val()
    prettyNum(paste0(val.ecr[1,1]))
  })

  output$tab <- DT::renderDT({
    req(mod_row$dt)
    # selected_row=input$data.tab_rows_selected
    # mod_df <- mod_df$x[selected_row,]
    isolate(mod_row$dt)
  }, escape=FALSE, selection = 'none',
  editable="all",
  options = list(
    columnDefs = list(
      list(
        visible = FALSE,
        targets = c(0)
      )
    )
  ),
  rownames=FALSE
  )

  proxy <- DT::dataTableProxy('tab')
  proxyy <- DT::dataTableProxy('data.tab')
  #shiny::observe({DT::replaceData(proxy, mod_df$x)})

  #######save - IT'S HERE I DON'T HOW I CAN DO? - still needs some work
  observeEvent(input$tab_cell_edit, {
                 newval=input$tab_cell_edit
                 str(newval)
                 i=newval$row
                 j=newval$col + 1
                 v=newval$value
                 mod_row$dt[i,j] <<- (DT::coerceValue(v,mod_row$dt[i,j]))
                 #replaceData(proxy, mod_row$dt,resetPaging = FALSE)

                 values$dat <- mod_row$dt

               })

  output$tb1 <- renderDT({values$dat}) ##  to check if modified data in the dialog can be displayed

  ## This event is triggered by the actionButton inside the modalDialog
  #  It closes the modal, and by setting values$modal_closed <- T
  observeEvent(input$save, {
    # values$modal_closed <- T  
    # removeModal()
    replaceData(proxy, mod_row$dt,resetPaging = FALSE)
    rowm <- mod_row$dt  ### modified row data
    df1 <- mod_df$x     ### orig data

    ## update orig data with modified row
    tmp <- left_join(df1, rowm, by="row_id") %>% transmute(row_id, ECR = ifelse(is.na(ECR.y), ECR.x, ECR.y),
                                                           BEM = ifelse(is.na(BEM.y), BEM.x, BEM.y),
                                                           BEE = ifelse(is.na(BEE.y), BEE.x, BEE.y),
                                                           FIN = ifelse(is.na(FIN.y), FIN.x, FIN.y) )
    mod_df$x <- tmp
    #replaceData(proxyy, tmp, resetPaging = FALSE)
  })

  # observe({
  #   if (values$modal_closed){
  #     rowm <- mod_row$dt  ### modified row data
  #     df1 <- mod_df$x  ### orig data
  #
  #     tmp <- left_join(df1, rowm, by="row_id") %>% transmute(row_id, ECR = ifelse(is.na(ECR.y), ECR.x, ECR.y),
  #                                                            BEM = ifelse(is.na(BEM.y), BEM.x, BEM.y),
  #                                                            BEE = ifelse(is.na(BEE.y), BEE.x, BEE.y),
  #                                                            FIN = ifelse(is.na(FIN.y), FIN.x, FIN.y) )
  #     mod_df$x <- tmp
  #     replaceData(proxyy, tmp, resetPaging = FALSE)
  #   }
  #
  # })

}
shinyApp(ui, server)
YBS
  • 19,324
  • 2
  • 9
  • 27
  • thanks to your help! I will check in my side. I ask me if it's really possible to do that? – Sylvain Dec 03 '20 at 18:48
  • I tried to use your code w/o any success. I don't understand why you use transmute function – Sylvain Dec 07 '20 at 17:37
  • That step is just to merge the updated value of `rowm` into `df1` data frame. However, updated value of `rowm` dataframe is not available outside the modal dialog box. That may require some javascript knowledge. – YBS Dec 08 '20 at 04:18
  • I think that we have to set up a list class for df1 instead of dataframe. I've seen a lot of thing with JS but I don't know. I wanted to make a 100% R code – Sylvain Dec 08 '20 at 06:41