Resetting fileInput in Shiny App - r

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.

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)

Related

How to save input to data frame, and use it later in Shiny?

I want to save the value from username input if it doesn't exist in data frame, and render text if it already exists (for reprex purpose).
Rendering text part works perfectly, but I don't know how to save it and use it later.
I want to save the value permanently, not only on current session
I've got this error:
Warning: Error in <-: invalid (NULL) left side of assignment
library(shiny)
ui <- fluidPage(
textInput("username", "username"),
actionButton("save", "Save!"),
textOutput("confirmation")
)
server <- function(input, output, session) {
df <- reactive(data.frame(column1 = "user1"))
exist <- reactive(input$username %in% df()$column1)
observeEvent(input$save, {
if (exist() == TRUE) {
output$confirmation <- renderText("Username already exists!")
} else {
df() <- rbind(df(), input$username) # <-- THIS dosn't work
}
})
}
shinyApp(ui, server)
EDIT:
Thanks to #I_O answer, I figured out this solution
reactiveVal() keep the changes in current session.
write_csv() and read_csv() part, allows app to use previously saved usernames.
saved_df <- read_csv("C:\\Users\\Przemo\\Documents\\R\\leaRn\\Shiny\\Moodtracker\\testers\\test_safe.csv")
ui <- fluidPage(
textInput("username", "username"),
actionButton("save", "Save!"),
textOutput("confirmation")
)
server <- function(input, output, session) {
df <- reactiveVal(saved_df)
exist <- reactive(input$username %in% df()$column1)
observeEvent(input$save, {
if (exist() == TRUE) {
output$confirmation <- renderText("Username already exists!")
} else {
output$confirmation <- renderText("")
df(rbind(df(), input$username))
write_csv(df(), "C:\\Users\\Przemo\\Documents\\R\\leaRn\\Shiny\\Moodtracker\\testers\\test_safe.csv")
}
})
}
shinyApp(ui, server)

Shiny - reactive not evaluating directly on textarea change?

I'm creating a Shiny app where user input is parsed and then used to create specific plots. These plots should only be created when the user pushes a corresponding button. The text however should be parsed immediatly when user input changes.
Simplified example:
library(shiny)
ui <- fluidPage(
textAreaInput("txt", "Parse this data:"),
actionButton("go", "Do something with data"),
textOutput("out")
)
server <- function(input, output, session) {
data <- reactive({
message("Parsing data...")
toupper(input$txt)
})
observeEvent(input$go, {
output$out <- data
})
}
shinyApp(ui, server)
The "Parsing data..." message initially only executes when pushing the button, not when changing the input of the textAreaInput.
On top of that, after pushing the button once, the input is parsed immediatly when changed but the output is updated immediatly as well. This also shouldn't happen, it should only change when the button is pressed again.
EDIT
With YBS's answer I found a solution, and using isolate() I don't even need an extra variable:
server <- function(input, output, session) {
data <- reactiveVal()
observeEvent(input$txt, {
message("Parsing data...")
data(toupper(input$txt))
})
observeEvent(input$go, {
output$out <- renderText({ isolate( data() ) })
})
}
Try this
library(shiny)
ui <- fluidPage(
textAreaInput("txt", "Parse this data:"),
actionButton("go", "Do something with data"),
textOutput("out")
)
server <- function(input, output, session) {
rv <- reactiveVal()
data <- reactive({
message("Parsing data...")
toupper(input$txt)
})
observeEvent(input$go, {
rv(data())
})
output$out <- renderText({rv()})
}
shinyApp(ui, server)

Jsoneditoutput is not displayed when given as reactive value in a shiny app

I have a shiny app which takes a csv file as input and after clicking 'submit' should display a jsoneditOutput. Besides this I have used a reset button which when clicked should reset the file input. But when I click submit I get: Error in read.table: 'file' must be a character string or connection.
library(shiny)
library(shinyjs)
library(tidyverse)
library(listviewer)
library(jsonlite)
library(SACCR)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
useShinyjs(),
fileInput('inFile', 'Choose 1st file'),
actionButton('submit', 'Submit'),
tags$hr(),
actionButton('reset', 'Reset')
),
mainPanel(
jsoneditOutput("choose")
)
)
)
server <- function(input, output, session) {
rv <- reactiveValues(
data = NULL,
clear = FALSE
)
########1st
observe({
req(input$inFile)
req(!rv$clear)
rv$data <- read.csv(input$inFile$datapath,header = T)
})
observeEvent(input$inFile, {
rv$clear <- FALSE
}, priority = 1000)
observeEvent(input$reset, {
rv$data <- NULL
rv$clear <- TRUE
reset('inFile')
}, priority = 1000)
output$choose <- renderJsonedit({input$submit
jsonedit(jsonlite::fromJSON(SACCR::SACCRCalculator(isolate(rv$data), JSON=TRUE)))
})
}
shinyApp(ui, server)
So the issue is with this line:
jsonedit(jsonlite::fromJSON(SACCR::SACCRCalculator(isolate(rv$data), JSON=TRUE)))
The SACCRCalculator function needs a .csv file, not an R dataframe. Try replacing rv$data with input$inFile$datapath.
Also, the SACCRCalculator function requires three files in total; the trades, CSA, and collaterals. So that line will need to be expanded to include all three files. It should end up looking something like:
SACCRCalculator(input$trades$datapath, input$csa$datapath, input$collaterals$datapath, JSON=TRUE)

Display the select file

I have written a code to read csv or excel file in shiny app. But what is happening is that, whatever I select first (say Excel file), the output is displayed. But once I switch to other (csv) the excel is still there and csv is not displayed. Not sure what wrong is there in the code. Could anyone please help me?
library(shinydashboard)
library(readxl)
ui <- dashboardPage(
dashboardHeader(title = "Loading data"),
dashboardSidebar(fileInput("datafile","Choose the csv file",multiple = TRUE,
accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
("Or"),
fileInput("datafile1","Choose the excel file",multiple = TRUE,
accept = c(".xlsx"))),
dashboardBody(
fluidRow(box(uiOutput("filter_70"),width = 5000))
))
server <- function(input,output){
output$contents <- renderTable({
file_to_read <- input$datafile
if(is.null(file_to_read))
return(NULL)
read.csv(file_to_read$datapath)
})
output$contents1 <- renderTable({
file_to_read1 <- input$datafile1
if(is.null(file_to_read1))
return(NULL)
read_excel(file_to_read1$datapath)
})
output$filter_70 <- renderUI(
if (!is.null(input$datafile)) {
tableOutput("contents")
} else if (!is.null(input$datafile1)) {
tableOutput("contents1")
}
)
}
shinyApp(ui, server)
as pointed out by #Rohit, reactive value once gets selected, it won't go back to null.
Keep your main structure unchanged, all you need is to monitor which file last changed. This requires creating a reactiveVal (last_selected) and then use observeEvent to track.
last_selected <- reactiveVal(NA)
observeEvent(input$datafile, {
last_selected("csv")
})
observeEvent(input$datafile1, {
last_selected("excel")
})
output$filter_70 <- renderUI({
req(last_selected())
if (last_selected()=="csv") {
tableOutput("contents")
} else if (last_selected()=="excel") {
tableOutput("contents1")
}
})

Dependent Dropdowns on Shiny

I am writing a shiny script where a file is uploaded, a dropdown appears with the column names from that file, and then a second dropdown appears with the unique values from the column in the file selected in the first dropdown. I was able to create the first dropdown, but am having trouble with the second dropdown. Here is my code thus far:
ui <- fluidPage(
titlePanel("File Upload Test"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose csv file",
multiple = T,
accept = c(".csv")),
uiOutput("y_input"),
uiOutput("target_input")),
mainPanel(
plotOutput("contents"))))
server <- function(input, output, session) {
inFile <- reactive({
if (is.null(input$file1)) {
return(NULL)
} else {
input$file1}
})
myData <- reactive({
if (is.null(inFile())) {
return(NULL)
} else {
read.csv(inFile()$datapath)}
})
output$y_input <- renderUI({
if (is.null(inFile())) {
return(NULL)
} else {
selectInput("y_output", "Select Y Variable", names(myData()))}
})
output$target_input <- renderUI({
if (is.null(input$y_input)) {
return(NULL)
} else {
selectInput("target_output", "Select Target Group",
myData( [,input$y_output])}
})
}
Any help here is appreciated! This is my first post on stack overflow, so if there are any formatting or clarity things in this post I can/should fix please let me know! Thanks!
First of all some tips to improve your code:
Use req
req(name_of_input) is shorthand for if(is.null(name_of_input)) return NULL. It will save you a few strokes while providing better readability.
Your reactive called inFile is unnecessary
Use input$file1$datapath instead. Again this is more concise while having better performance as well.
myData <- reactive({
req(input$file1)
read.csv(input$file1$datapath)
})
And finally the problem:
Your reference to myData is wrong. The subsetting part of [,input$y_output] should be outside of the parentheses, like this: myData()[,input$y_output]. Keep in mind that even though reactives look like functions they don't take any arguments.
Full server.R:
server <- function(input, output, session) {
myData <- reactive({
req(input$file1)
read.csv(input$file1$datapath)
})
output$y_input <- renderUI({
req(input$file1)
selectInput("y_output", "Select Y Variable", names(myData()))
})
output$target_input <- renderUI({
req(input$file1)
selectInput("target_output", "Select Target Group",
myData()[,input$y_output]
)
})
}
ps: Welcome to stackoverflow! :)

Resources