Search code examples
rshinyshinyalert

R Shiny validate column number input file


I'm replicating the example of the Shiny File Upload app. As you can see I added a validate function for the file type. I also set fixed column names, because I want to allow the user to only upload date for a maximum of 5 columns.

Right now when the user uploads a file that has more columns than allowed a R message will be displayed: more columns than column names.

I'd like to have a validate/require function that checks the number of columns and shows a more user friendly message. My idea was to use the validate function with (ncol(input$file1)<=5)==TRUE but somehow that does not seem to work. Anyone an idea of how to check the number of columns on the input file and change the displayed user message? (if it can be done with Shinyalert that'd be amazing!).

Lastly, I am also struggling to find out how I wrap the table I get around a reactive dataframe that I can recall later on.

Thanks in advance!

library(shiny)
library(tools)

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")),

      # Horizontal line ----
      tags$hr(),

      # Input: Select separator ----
      radioButtons("sep", "Separator",
                   choices = c(Comma = ",",
                               Semicolon = ";",
                               Tab = "\t"),
                   selected = ","),

      # Input: Select quotes ----
      radioButtons("quote", "Quote",
                   choices = c(None = "",
                               "Double Quote" = '"',
                               "Single Quote" = "'"),
                   selected = '"'),

      # Horizontal line ----
      tags$hr(),

      # Input: Select number of rows to display ----
      radioButtons("disp", "Display",
                   choices = c(Head = "head",
                               All = "all"),
                   selected = "head")

    ),

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

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

    )

  )
)

server <- function(input, output) {

  output$contents <- renderTable({

    # input$file1 will be NULL initially. After the user selects
    # and uploads a file, head of that data file by default,
    # or all rows if selected, will be shown.

    req(input$file1)

    # when reading semicolon separated files,
    # having a comma separator causes `read.csv` to error
    tryCatch(
      {
        df <- read.csv(input$file1$datapath,
                       header = F,
                       sep = input$sep,
                       quote = input$quote,
                       col.names = c("COL1","COL2","COL3","COL4","COL5"),
                       check.names = F)
      },

      validate(
        need(file_ext(input$file1$datapath) %in% c(
          'text/csv',
         'text/comma-separated-values',
          'text/tab-separated-values',
          'text/plain',
          'csv'
        ), "Data was not recognized. Please use a CSV file!")),

      error = function(e) {
        # return a safeError if a parsing error occurs
        stop(safeError(e))
      }
    )

    if(input$disp == "head") {
      return(head(df))
    }
    else {
      return(df)
    }

  })

}

shinyApp(ui,server)







Solution

  • I tried to built a sample program where user can only upload csv dataset with only 5 columns. You can change as per your requirement.

    UI.R

    library(shiny)
    library(shinydashboard)
    library(shinyjs)
    library(shinyalert)
    
    
    dashboardPage(
       dashboardHeader(title = "Basic dashboard"),
       dashboardSidebar(
          sidebarMenu(
             menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard"))
          )
       ),
       dashboardBody(
          useShinyalert(),
          tabItems(
             tabItem(tabName = "dashboard",
                     fluidRow(
                               column(3,
    
                                         fileInput("file1", "Choose CSV File",
                                                   multiple = FALSE,
                                                   accept = c("text/csv",
                                                              "text/comma-separated-values,
                                                                text/plain",
                                                              ".csv"))
                                      )
    
                            ),
                     fluidRow(
                        tableOutput("contents")
                            )
                     )
          )
       )
    )
    

    Server.R

    library(shiny)
    library(shinydashboard)
    
    
    shinyServer(function(input,output){
    
      output$contents <- renderTable({
        inFile <- input$file1
    
        if (is.null(inFile))
        {
          returnValue()
        }
        else
        {
          data<-read.csv(inFile$datapath)
          if(ncol(data)<5)
          {
            shinyalert("Column Error","Uploaded Data has less than 5 Col",type="error")
            returnValue()
          }
          else if(ncol(data)>5)
          {
            shinyalert("Column Error","Uploaded Data has more than 5 Col",type = "error")
            returnValue()
          }
          else
          {
            return(data)
          }
        }
    
      })
    
    })