Search code examples
rshinyshinymodules

Multiple UI Output Based on File Upload Using Shiny Modules


Dataset Viewer
Hello, I am attempting to create a shiny application that allows to user to view their uploaded datasets individually.

When there is no file uploaded a message appears asking the user to upload their file...once a csv file is uploaded, the message disappears and shows the users uploaded datasets.

What I've tried
I've tried: using conditionalPanels in app.R & upload.R, creating a separate R file exclusively for each ui condition. I believe my issue is that output$table (function that renders mainpanel ui) is not being triggered after the file uploads.

My issue
Once the user uploads a csv file(any readable csv file), the pre-existing message is not being replaced by the uploaded datasets.

upload.R

data = list()
numDatasets = 0

uploadSideUI <- function(id) {
  ns <- NS(id)
  tagList(
    h2("Dataset Viewer"),
    fileInput(ns("file"),label = "Upload File", multiple = FALSE, accept = ".csv")
  )
}

uploadMainUI <- function(id) {
  ns <- NS(id)
  uiOutput(ns("table"))
}

uploadServer <- function(id) {
  moduleServer(id, function(input,output,session){
    
    observeEvent(eventExpr = input$file,
                 handlerExpr = {
                   df <- read.csv(file = input$file$datapath,header = FALSE)
                   data <<- c(data,list(df))
                   numDatasets <<- numDatasets + 1
                 })
    
    output$table <- renderUI({
      if(numDatasets ==0){
        h2("please upload file")
      }else{
        req(input$file)
        print(numDatasets)
        lapply(1:numDatasets,function(i) {
          dataframe = data[[i]]
          tagList(
            h2(paste("dataset",i)),
            hr(),
            datatable(dataframe,rownames = FALSE, option = list(scrollY="300px",searching=FALSE)),
            br()
          )
      })
      }
    })
  })
}

app.R

#app.R
library(DT)
library(shiny)
source("testModule.R")
ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      uploadSideUI("uploadPage")
    ),mainPanel(
      uploadMainUI("uploadPage")
    )
  )
)

server <- function(input, output, session) {
  uploadServer("uploadPage")
}

shinyApp(ui = ui, server = server)

I am new to the modulization process in shiny, so if you have any other suggestions please point them out! Thanks in advance!


Solution

  • Try this

    uploadServer <- function(id) {
      moduleServer(id, function(input,output,session){
        rv <- reactiveValues(numDatasets = 0)
        observeEvent(eventExpr = input$file,
                     handlerExpr = {
                       df <- read.csv(file = input$file$datapath,header = FALSE)
                       data <<- c(data,list(df))
                       rv$numDatasets <<- rv$numDatasets + 1
                     })
        
        output$table <- renderUI({
          if(rv$numDatasets == 0){
            h2("please upload file")
          }else{
            req(input$file)
            print(rv$numDatasets)
            lapply(1:rv$numDatasets,function(i) {
              dataframe = data[[i]]
              tagList(
                h2(paste("dataset",i)),
                hr(),
                datatable(dataframe,rownames = FALSE, option = list(scrollY="300px",searching=FALSE)),
                br()
              )
            })
          }
        })
      })
    }