Search code examples
rshinyrscriptrshiny

How to activate undo button for previous 4 actions in R Shiny


I am creating a R shiny app with buttons like browse, SpitColumn, deleting rows, values, and columns. Everything functions as it should. I have included a "undo" button, but I'm not sure how to make it work in the server function, also how to undo the previous four actions.

Could someone please assist me?

csv data

ID  Type   Range
21  A1 B1   100
22  C1 D1   200
23  E1 F1   300

app.R

library(shiny)
library(reshape2)
library(DT)
library(tibble)


###function for deleting the rows
splitColumn <- function(data, column_name) {
  newColNames <- c("Unmerged_type1", "Unmerged_type2")
  newCols <- colsplit(data[[column_name]], " ", newColNames)
  after_merge <- cbind(data, newCols)
  after_merge[[column_name]] <- NULL
  after_merge
}
###_______________________________________________
### function for inserting a new column

fillvalues <- function(data, values, columName){
  df_fill <- data
  vec <- strsplit(values, ",")[[1]]
  df_fill <- tibble::add_column(df_fill, newcolumn = vec, .after = columName)
  df_fill
}

##function for removing the colum

removecolumn <- function(df, nameofthecolumn){
  df[ , -which(names(df) %in% nameofthecolumn)]
}

### use a_splitme.csv for testing this program

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("file1", "Choose CSV File", accept = ".csv"),
      checkboxInput("header", "Header", TRUE),
      actionButton("Splitcolumn", "SplitColumn"),
      uiOutput("selectUI"),
      actionButton("deleteRows", "Delete Rows"),
      textInput("textbox", label="Input the value to replace:"),
      actionButton("replacevalues", label = 'Replace values'),
      actionButton("removecolumn", "Remove Column"),
      actionButton("Undo", 'Undo')
    ),
    mainPanel(
      DTOutput("table1")
    )
  )
)

server <- function(session, input, output) {
  rv <- reactiveValues(data = NULL)
  
  observeEvent(input$file1, {
    file <- input$file1
    ext <- tools::file_ext(file$datapath)
    
    req(file)
    
    validate(need(ext == "csv", "Please upload a csv file"))
    
    rv$data <- read.csv(file$datapath, header = input$header)
    
  })
  
  output$selectUI<-renderUI({
    req(rv$data)
    selectInput(inputId='selectcolumn', label='select column', choices = names(rv$data))
  })
  
  
  observeEvent(input$Splitcolumn, {
    rv$data <- splitColumn(rv$data, input$selectcolumn)
  })
  
  observeEvent(input$deleteRows,{
    if (!is.null(input$table1_rows_selected)) {
      rv$data <- rv$data[-as.numeric(input$table1_rows_selected),]
    }
  })
  
  output$table1 <- renderDT({
    rv$data
  })
  observeEvent(input$replacevalues, {
    rv$data <- fillvalues(rv$data, input$textbox, input$selectcolumn)
  })
  observeEvent(input$removecolumn, {
    rv$data <- removecolumn(rv$data,input$selectcolumn)
  })
}

shinyApp(ui, server)

Solution

  • Just keep the original file you read in as a separate reactiveValues object and assign it to rv$data when the Undo button is pressed. Try this

    server <- function(session, input, output) {
      rv <- reactiveValues(data = NULL, orig=NULL)
      
      observeEvent(input$file1, {
        file <- input$file1
        ext <- tools::file_ext(file$datapath)
        
        req(file)
        
        validate(need(ext == "csv", "Please upload a csv file"))
        
        rv$orig <- read.csv(file$datapath, header = input$header)
        rv$data <- rv$orig
      })
      
      output$selectUI<-renderUI({
        req(rv$data)
        selectInput(inputId='selectcolumn', label='select column', choices = names(rv$data))
      })
      
      
      observeEvent(input$Splitcolumn, {
        rv$data <- splitColumn(rv$data, input$selectcolumn)
      })
      
      observeEvent(input$deleteRows,{
        if (!is.null(input$table1_rows_selected)) {
          rv$data <- rv$data[-as.numeric(input$table1_rows_selected),]
        }
      })
      
      output$table1 <- renderDT({
        rv$data
      })
      observeEvent(input$replacevalues, {
        rv$data <- fillvalues(rv$data, input$textbox, input$selectcolumn)
      })
      observeEvent(input$removecolumn, {
        rv$data <- removecolumn(rv$data,input$selectcolumn)
      })
      observeEvent(input$Undo, {
        rv$data <- rv$orig
      })
    }