Validate fileInput data immediately

Suppose I have a file input widget and my goal is to validate two things immediately once that file is read in via the shiny app. First, I want to limit the number of columns to N. If a file has more than N columns, I want a warning printed to screen right away.

Second, I want to check if the data file contains specific columns. If a required column is not included once the file is read in, then print an alert to screen.

server <- function(input, output) {
  output$contents <- renderTable({
    inFile <- input$file1
    if (is.null(inFile))
      return(NULL)
    read.csv(inFile$datapath, header = input$header)
  })
}

Inside the server side fileInput I could do something like:

dat <- read.csv(inFile$datapath, header = input$header)
reqs <- c('req1', 'req2') # define required variables
nms <- colnames(dat)
test <- all(reqs %in% nms)
validate(need(test, "You don't have the right data"))

This attempt didn't quite work out, so I'm curious if anyone else has success doing a real time validator on data read in as it occurs.

Hi hdoran,

What exactly didn't quite work in your attempt?

In case it might help, I have created a reprex using the example Shiny app from the fileInput documentation as well as the example you provided in your original post:

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("file1", "Choose CSV File",
                accept = c(
                  "text/csv",
                  "text/comma-separated-values,text/plain",
                  ".csv")
      ),
      tags$hr(),
      checkboxInput("header", "Header", TRUE)
    ),
    mainPanel(
      tableOutput("contents")
    )
  )
)

server <- function(input, output) {
  output$contents <- renderTable({
    # input$file1 will be NULL initially. After the user selects
    # and uploads a file, it will be a data frame with 'name',
    # 'size', 'type', and 'datapath' columns. The 'datapath'
    # column will contain the local filenames where the data can
    # be found.
    inFile <- input$file1
    
    if (is.null(inFile))
      return(NULL)
    
    file_contents <- read.csv(inFile$datapath, header = input$header)
    
    required_columns <- c('req1', 'req2')
    column_names <- colnames(file_contents)
    max_columns <- 10
    
    shiny::validate(
      need(ncol(file_contents) <= max_columns, "Your data has too many columns"),
      need(all(required_columns %in% column_names), "You don't have the right data")
    )
    
    file_contents
    
  })
}

shinyApp(ui, server)

Created on 2019-09-11 by the reprex package (v0.3.0)

This app will display the error message(s) in the location of the "contents" tableOutput if either of the two conditions are not met; otherwise, the data from the file will be displayed. I included a verification for a maximum number of columns, as you stated that you wanted to check for this first.

Note that this implementation will display both error messages simultaneously if both conditions fail. If you prefer that they only display one at a time, you can chain conditions together with the %then% operator, as described in this article. This could be done in the above reprex by modifying the shiny::validate() call as follows:

`%then%` <- shiny:::`%OR%`

shiny::validate(
  need(ncol(file_contents) <= max_columns, "Your data has too many columns") %then%
    need(all(required_columns %in% column_names), "You don't have the right data")
)

Hope this helps!

2 Likes