简体   繁体   中英

Upload a file in a shiny app and set its name through a textInput()

I have a simple shiny app below. In this app I want the user to be able to upload his own csv and then automatically this will be added as a choice in the checkbox group below the other dataset "DB" (which I create in my original app). I did that by using an observer and a reactive list in which I stote the file names. The new file will have its default name initially but then the user will be able to change it to a name of his choice with the "Set Filename" textInput(). Then when the user chooses a file it will be displayed as a table. The problem is that Im missing something and when I add the 2nd file the first becomes NA and no tables are displayed.

#ui.r
library(shiny)
library(rlist)
# Define UI for data upload app ----
ui <- fluidPage(

  # App title ----
  titlePanel("Uploading Files"),

  # Sidebar layout with input and output definitions ----
  sidebarLayout(

    # Sidebar panel for inputs ----
    sidebarPanel(

      # Input: Select a file ----
      fileInput("file1", "Choose CSV File",
                multiple = FALSE,
                accept = c("text/csv",
                           "text/comma-separated-values,text/plain",
                           ".csv")),
      uiOutput("checkbox"),
      uiOutput("text")

    ),

    # Main panel for displaying outputs ----
    mainPanel(

      # Output: Data file ----
      tableOutput("contents")

    )

  )
)
#server.r
server <- function(input, output) {
  output$text<-renderUI({
  textInput("filename","Set Filename",value = "Set Name")
  })
  New <- reactive({
    req(input$file1)
    df <- read.csv(input$file1$datapath)

  })

  D.B <- reactive({
    if("D.B"%in% input$datasetSelector){
    x <- read.csv("something.csv", stringsAsFactors = F)
    }
  })

  fileOptions <- reactiveValues(currentOptions=c("D.B."))

  observeEvent(input$file1, {
    fileOptions$currentOptions = list.append(fileOptions$currentOptions, "New")
  })
  output$checkbox<-renderUI({
    if(length(fileOptions$currentOptions)==1){
    checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = fileOptions$currentOptions[[1]]
    )}
    else{
    names(fileOptions$currentOptions)[[2]]<-input$filename  
    checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = fileOptions$currentOptions
   )}
  })
  output$contents <- renderTable({
    input$dataSelector
  })


}

I had to overhaul the server and ui to use the built in shiny features to make this easier. That being said this does everything you want. Note that I am not showing any table making or data processing here, just the file renaming and uploading.

# Define UI for data upload app ----
ui <- fluidPage(

  # App title ----
  titlePanel("Uploading Files"),

   # Sidebar layout with input and output definitions ----
  sidebarLayout(

    # Sidebar panel for inputs ----
    sidebarPanel(

       # Input: Select a file ----
       fileInput("file1", "Choose CSV File",
                multiple = FALSE,
                accept = c("text/csv",
                       "text/comma-separated-values,text/plain",
                       ".csv")),
      checkboxGroupInput("datasetSelector","Data Files", choices=c("D.B")),
      textInput("filename","Set Filename",value = "Set Name")

    ),

    # Main panel for displaying outputs ----
      mainPanel(

      # Output: Data file ----
      tableOutput("contents")

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

  observeEvent(input$filename, {

  req(input$file1)
  Name<-input$filename
  updateCheckboxGroupInput(session,"datasetSelector", choices=c("D.B",Name))
  })

  observeEvent(input$file1, {

    Data<-input$file1$datapath
    Name<-input$filename
    New <- read.csv(Data)
    updateCheckboxGroupInput(session,"datasetSelector", 
      choices=c("D.B",input$file1$name))
  })

  #Data proccesing code 
}

I used a checkboxGroupInput and textInput which are shiny inputs that can be defined in the UI. These set a standard input and allow us to use functions like updateGroupCheckboxInput which cannot be used on a general UI rendering. Now we can observe any input into the fileInput and textInput and run code based on when this is done.

When a user uploads a file, the name of the checkbox is set to the uploaded filename. When the user changes the input$filename we can observe that and change the checkbox name accordingly. This way anytime a new file is uploaded it will overwrite the existing checkbox name with a new file name from the upload, which in turn can be overwritten by any input to our text field.

Getting rid of the reactive DB and simply observing any input into the check boxes we can simply assign the data based on how many boxes are checked, since if two are checked we should load DB and the uploaded file; If one is checked we can check the name for "DB", the assigned file name, or the text field name, and show the correct file accordingly. The DB file gets loaded consistently while the input file only gets loaded when the checkbox is selected. Since there is no checkbox unless there is an uploaded file, that should cover us there.

#Data Processing Code
observeEvent(input$datasetSelector, {

  #Constant
  D.B<- read.csv("somthing.csv", stringsAsFactors = F)

  Selected<-input$datasetSelector
  L_Sel<-length(Selected)

  if(L_Sel==2){
    Data<-read.csv(input$file1$datapath)
    dataSelector<-list(Data,D.B)
    print("A")
  }else if(Selected=="D.B"){
    dataSelector<-D.B
    print("B")
  }else if(Selected==input$file1$name|Selected==input$filename){
    Data<-read.csv(input$file1$datapath)
    dataSelector<-Data
    print(Data)
    print("C")
  }else{
    dataSelector=NA
  }

  output$contents<-renderTable({
    dataSelector
  })

  })

Note we also put the output under the observeEvent for the checkbox as well, therefore no table will initialize unless you set a selected value for the checkbox upon deploying. I am not sure how you want to display both tables so that will need some work, but just work within the if/statement and observeEvent for the check boxes.

The program knows when both check boxes are selected and makes a list of the two files/data, but I am not sure on how you were planning on displaying these. You would want to include that work under the if(L_Sel==2){..} section though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM