Asked  7 Months ago    Answers:  5   Viewed   179 times

I have been trying for a long time to reset fileInput in a Shiny app and read solutions to similar problems, but my problem still persists. Most solutions ultimately lead to using Dean Attali's brilliant shinyjs package and the reset() function therein. Here's what my code looks like after following these instructions:

library(shiny)
library(shinyjs) 
library(xlsx) 
library(tidyverse) 

ui <- fluidPage(
  useShinyjs(),
  fileInput('inFile', 'Choose file'),
  actionButton('reset', 'Reset'),
  radioButtons("type","Choose file type",choices = c('csv','xls')),
  tableOutput('tbl')
)

server <- function(input, output, session) {

  rv <- reactiveValues(data = NULL)

  observe({
    req(input$inFile)
    if(input$type=='csv'){
      rv$data <- read.csv(input$inFile$datapath)
    }
    if(input$type=='xls'){
      rv$data <- read_excel(input$inFile$datapath)
    }

  })

  observeEvent(input$reset, {
    rv$data <- NULL
    reset('inFile')
  })

  output$tbl <- renderTable({
    rv$data
  })
}

shinyApp(ui, server)

I initially select the csv option and am able to load a csv file. Now when I press the reset button, it clears the data. As soon as I select the xls option, I get an error:

Listening on http://127.0.0.1:4135
Warning: Error in : Unknown file extension: csv

Which makes me believe that input$inFile$datapath still contains the pathname of the csv file that I selected earlier. I have run out of ideas on how to solve this problem and would greatly appreciate some help please.

 Answers

5

Ideally fileInput would properly reset, but you can do this as a workaround. Add an explicit flag variable (rv$clear) to indicate whether you're in cleared state, and toggle that on and off in high-priority observers when reset and upload occur, respectively.

library(shiny)
library(shinyjs) 
library(xlsx) 
library(tidyverse) 

ui <- fluidPage(
  useShinyjs(),
  fileInput('inFile', 'Choose file'),
  actionButton('reset', 'Reset'),
  radioButtons("type","Choose file type",choices = c('csv','xls')),
  tableOutput('tbl')
)

server <- function(input, output, session) {

  rv <- reactiveValues(
    data = NULL,
    clear = FALSE
  )

  observe({
    req(input$inFile)
    req(!rv$clear)

    if(input$type=='csv'){
      rv$data <- read.csv(input$inFile$datapath)
    }
    if(input$type=='xls'){
      rv$data <- read_excel(input$inFile$datapath)
    }

  })

  observeEvent(input$inFile, {
    rv$clear <- FALSE
  }, priority = 1000)

  observeEvent(input$reset, {
    rv$data <- NULL
    rv$clear <- TRUE
    reset('inFile')
  }, priority = 1000)

  output$tbl <- renderTable({
    rv$data
  })
}

shinyApp(ui, server)
Friday, November 12, 2021
 
5

This is a working example based on using the "webkitdirectory" attribute. At the moment the attribute is supported by Chrome, Opera and Safari (mobile and desktop) and it should be supported in Firefox 49 to be released in September. More about this here. It work with subdirectories also.

It requires using the tags keyword in ui.R. I have tested it by uploading three csv files each contaning three numbers separeted by a coma. Tested locally and on shinyapps.io with Chrome and Opera. This is the code:

ui.R

    library(shiny)
    library(DT)

    shinyUI(tagList(fluidPage(theme = "bootstrap.css",
                      includeScript("./www/text.js"),
                      titlePanel("Folder content upload"),

                      fluidRow(
                              column(4,
                                     wellPanel(
                                             tags$div(class="form-group shiny-input-container", 
                                                      tags$div(tags$label("File input")),
                                                      tags$div(tags$label("Choose folder", class="btn btn-primary",
                                                                          tags$input(id = "fileIn", webkitdirectory = TRUE, type = "file", style="display: none;", onchange="pressed()"))),
                                                      tags$label("No folder choosen", id = "noFile"),
                                                      tags$div(id="fileIn_progress", class="progress progress-striped active shiny-file-input-progress",
                                                               tags$div(class="progress-bar")
                                                      )     
                                             ),
                                             verbatimTextOutput("results")
                                     )
                              ),
                              column(8,
                                     tabsetPanel(
                                             tabPanel("Files table", dataTableOutput("tbl")),
                                             tabPanel("Files list", dataTableOutput("tbl2"))
                                     )
                              )
                      )
    ),
    HTML("<script type='text/javascript' src='getFolders.js'></script>")
    )

    )          

server.R

    library(shiny)
    library(ggplot2)
    library(DT)

    shinyServer(function(input, output, session) {
            df <- reactive({
                    inFiles <- input$fileIn
                    df <- data.frame()
                    if (is.null(inFiles))
                            return(NULL)
                    for (i in seq_along(inFiles$datapath)) {
                            tmp <- read.csv(inFiles$datapath[i], header = FALSE)  
                            df <- rbind(df, tmp)
                    }
                    df

            })
            output$tbl <- DT::renderDataTable(
                    df()
            )
            output$tbl2 <- DT::renderDataTable(
                    input$fileIn
            )
            output$results = renderPrint({
                    input$mydata
            })

    })

text.js

window.pressed = function(){
        var a = document.getElementById('fileIn');
        if(a.value === "")
        {
            noFile.innerHTML = "No folder choosen";
        }
        else
        {
            noFile.innerHTML = "";
        }
    };

getFolders.js

     document.getElementById("fileIn").addEventListener("change", function(e) {

            let files = e.target.files;
            var arr = new Array(files.length*2);
            for (let i=0; i<files.length; i++) {

            //console.log(files[i].webkitRelativePath);
            //console.log(files[i].name);
            arr[i] = files[i].webkitRelativePath;
            arr[i+files.length] = files[i].name;


            }

            Shiny.onInputChange("mydata", arr);

    });

Let me know if this helps.

Tuesday, June 22, 2021
 
Claudio
 
4

I found a solution using the onclick function from the shinyjs package.

    library(shinyjs)
    ui <- fluidPage(
      useShinyjs(),
      actionButton("showtxt", "Show/Download File")
    )


    server <- function(input, output, session){
      observeEvent(input$showtxt,{
        # Write some text
        write.table(c("Test"), file = "www/test.txt")
      })


      # Call Onclick
      onclick("showtxt", runjs("window.open('test.txt')"))
    }


    shinyApp(ui=ui,server=server) 
Sunday, October 10, 2021
3

(Posted solution on behalf of the OP).

I forgot to remove # from #library(flexdashboard), therefore the function gauge could not be find and gauge could not be rendered...

Monday, October 11, 2021
 
nomie
 
2

You need to use observeEvent instead of eventReactive. Your code will look something like this:

library(shiny)
library(shinyBS)
library(dplyr)
library(shinydashboard)


# javascript code to collapse box
jscode <- "
shinyjs.collapse = function(boxid) {
$('#' + boxid).closest('.box').find('[data-widget=collapse]').click();
}
"

#Design sidebar
sidebar <- dashboardSidebar(width = 225, collapsed=F, 
                            sidebarMenu(id="tabs",
                                        menuItem("zz", tabName = "zz", selected=TRUE)))

#Design body 
body <- dashboardBody(shinyjs:::useShinyjs(), 
                      shinyjs:::extendShinyjs(text = jscode),
                      tabItems(
                        tabItem(tabName = "zz", 
                                fluidRow(box(actionButton('go','Go', class='btn btn-info', icon=icon('play-circle-o','fg-lg'))),
                                         box(id="B1", collapsible=T, collapsed = T, status = "primary", color="blue", solidHeader = T, 
                                             title="Test")))))

Header <- dashboardHeader()

#Show title and the page (includes sidebar and body)
ui <- dashboardPage(Header, sidebar, body)


server <- shinyServer(function(input, output, session){

  observeEvent(input$go,{js$collapse("B1")})
})

shinyApp( ui = ui, server = server)

Hope it helps!

Tuesday, December 7, 2021
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :