I want to make a Shiny App in which the user can press an actionbutton which would then trigger some code on the server side creating a file in the www folder and then opens/downloads the file.
Suppose the file is test.txt (in my case it would be a variety of R, Excel, and exe files which will be copied from different folders on a drive to the www folder).
My first try was to use the actionbutton with the onclick option as shown below
ui <- fluidPage(
actionButton("showtxt", "Show/Download File", onclick = "window.open('test.txt')")
)
server <- function(input, output, session){
observeEvent(input$showtxt,{
# Write some text
write.table(c("Test"), file = "www/test.txt")
})
}
shinyApp(ui=ui,server=server)
But this doesn't work since the onclick action is done before the observevent is evaluated.
I then tried to call a function inside to the onclick option as shown below
CreateFileAndLink <- function(){
write.table(c("Test"), file = "www/test.txt")
return("window.open('test.txt')")
}
ui <- fluidPage(
actionButton("showtxt", "Show/Download File", onclick = CreateFileAndLink())
)
server <- function(input, output, session){}
shinyApp(ui=ui,server=server)
This works but has the downside that now the file is created when upon opening the Shiny App as opposed to creating the file when the user clicks the actionbutton. This is very inefficient if I were to use this piece of code multiple times in an App with relatively large files.
Maybe it is possible to make sure that the observevent is executed before the onclick-action, or maybe use the onclick option on the server side.
Any help would be greatly appreciated!
Cheers
UPDATE:
I found out that the great shinyjs package by Dean Attali contains a onclick function that might be of help here. I tried to run the code below but it didn't work :/
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", "window.open('test.txt')")
})
}
shinyApp(ui=ui,server=server)
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)
Related
I wrote a R script (MAIN.R) that converts PDF tables to CSV. When I run MAIN.R as an individual file, it functions well. I've tried it many times.
Currently, I'm working on a R shiny app that uses "MAIN.R" as a source and takes a pdf file as input. When I push the submit button, the output should appear in the MAIN panel. Unfortunately, the submit button does not function as intended.
May anyone please assist me with this, as I am new to Shiny?
UI.R
shinyUI(fluidPage(
titlePanel("DATASET CONVERSION"),
sidebarLayout(
fileInput("filein", label = h2("Select a file to convert.")),
submitButton("Submit")
),
mainPanel(
tableOutput("Dataset")
)
)
)
Server.R
source("MAIN.R")
shinyServer(function(input, output) {
outputdf <- reactive({ input$filein
})
output$Dataset <- renderTable({
outputdf()
})
})
Your Submit button is not currently linked to anything, so it will not do anything. If I am reading the code right, you are just taking the input dataset and storing it as the output of outputdf. Your output$Dataset then just picks up that outputdf and displays it as-is, without any work being done on it.
You use an action button like so:
## In UI.R
actionButton("execute", "Execute the Main Function")
## In Server.R
observeEvent(input$execute, {
## Do stuff here
})
Note that the actionButton has two parameters, inputID (which is how you refer to it) and text to display on top. For example, with input$filein, 'filein' is the inputID.
In Server.R, observeEvent won't do anything until it detects a change in input$execute, which happens when someone clicks the button. That is where you put your code to do stuff.
Now, in output$Dataset, you need to access the results of whatever you did in that observeEvent. One way to do that is to use a reactiveValue. This is just like a reactive, but instead of a function, it stores a data element. Initialize it as an empty dataframe, and then update it in the observeEvent. Something like this:
## In Server.R
treated_output <- reactiveValue(data.frame())
observeEvent(input$execute, {
## Run the function on the file
updated <- main_function(input$filein)
# Update your reactiveValue
treated_output(updated)
})
output$Dataset <- renderTable({
treated_output()
})
Does this make sense?
Is it possible to see the changes in UI (only the UI and not server) after I make changes in my code, without having to restart the server/refresh the page? If cache needs to be cleared, can that also be done?
You could use reactiveFileReader to regularly source the code you'd save in another file, and renderUI()/uiOutput to display that dynamic UI:
app.R
library(shiny)
ui <- uiOutput("ui")
server <- function(input, output, session) {
ui <- reactiveFileReader(1000, session, "source.R", source)
output$ui <- renderUI(ui())
}
shinyApp(ui = ui, server = server)
source.R
fluidPage(
textInput("text", "text"),
textInput("text2", "text")
)
You still have to find out howto get rid of that "TRUE":
In a Shiny app, I am trying to have an eventReactive triggered either with an actionbutton OR when the session opens.
I've tryed the below code using session$clientData but it doesn't work.
Also tried to play with toggleModal from shinyBS but still no chance. Any help much appreciated. Thanks!
library(shiny)
ui <- fluidPage(
actionButton("go", "Go"),
numericInput("n", "n", 50),
plotOutput("plot")
)
server <- function(session, input, output) {
randomVals <- eventReactive({input$go
session$clientData}, {
runif(input$n)
})
output$plot <- renderPlot({
hist(randomVals())
})
}
shinyApp(ui, server)
Actually figured this out. On my question above, I tried to simplified my code, and doing so actually fixed the issue...
randomVals <- eventReactive({input$go
session$clientData}
works as expected (i.e. you get a chart when opening the session even without clicking on go), while
randomVals <- eventReactive({session$clientData
input$go}
doesn't work (i.e you need to click on go to get your first chart
So I guess the order in the event {} matters, which I didn't know
I am finally trying to make a Shiny app. I am trying to upload a .xlsx file to the app, and then apply some analysis and download the output as a separate .xlsx file. The code for analysis and taking output works when run directly outside Shiny and I use it on daily, so I am simply trying to call it via source and save the duplicated work. Here is what I am trying with Shiny.
I was having problems in calling the file from the W2S.R script, while avoiding errors. I found a way to avoid the errors. The below code is a barebones model of that. However, now I cannot get the actual input to work (Output works fine, one table output on-screen and one XLSX output off-screen).
I am using W2S <- input$W2S1 inside W2S.R script, but it is not recognising the variable input, which it does if used in the server function directly. How do I get it to work inside the script? Or is there any other workaround?
library(shiny)
ui <- fluidPage(
titlePanel(h1("Goods In Transit Analysis", align="center")),
sidebarLayout(
sidebarPanel(
fileInput("W2S1", label="Select GIT W2S file")
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output) {
output$contents <- renderTable(if(is.null(input$W2S1)){return(NULL)}
else{source("./W2S.R")})
}
shinyApp(ui = ui, server = server)
I will update once I get the input to work. Please help.
EDIT: Made some progress, as noted above. So updated the new code.
Finally nailed it. I needed an observe function and use the $datapath argument.
library(shiny)
ui <- fluidPage(
# Application title
titlePanel(h1("Goods In Transit Analysis", align="center")),
# Sidebar iputs
sidebarLayout(
sidebarPanel(
fileInput(inputId="W2S", label="Select GIT W2S file")
),
# On Screen output
mainPanel(
h3(textOutput("filePath")),
tableOutput("contents")
)
)
)
# Underlining code for output
server <- function(input, output) {
observe({
source("./Code/W2S.R")
W2S <- input$W2S
output$contents <- renderTable(if(is.null(W2S)){return(NULL)}
else{W2S_F(W2S$datapath)})
})
}
# Run the application
shinyApp(ui = ui, server = server)
In my Shiny app I want to open several URL's with a short delay between opening.
Here is some example code that works just fine when I run the app in my RStudio.
library(shiny)
URLs <- c("http://www.google.com", "http://www.stackoverflow.com")
ui <- fluidPage(
actionButton(
"click",
"Click here to open several browser tabs"
)
)
server <- function(input, output){
observeEvent(input$click, {
for (i in URLs){
browseURL(i)
Sys.sleep(1) #Short delay of 1 second
}
})
}
shinyApp(ui, server)
However, when I run this app on shinyapps.io, browseURL() doesn't work (as mentioned here).
Does anyone know how to open multiple browser tabs with a short delay between opening them, so that it also works when the app is deployed on shinyapps.io?
Would it be possible with R code or is JavaScript necessary?
This is a pretty old question, but answering in case others stumble upon while searching.
As mentioned in the reference you linked, I think you need to use some JS to accomplish this task. Below is an example of using the shinyjs package to define a shiny compatible browseURL function. Once we have the function defined we add a few lines to the ui and then call it in the server as js$browseURL().
Note that a pop-up blocker might block the effects of opening multiple tabs. Check your blocker settings if things don't seem to work.
library(shiny)
library(shinyjs)
# define js function for opening urls in new tab/window
js_code <- "
shinyjs.browseURL = function(url) {
window.open(url,'_blank');
}
"
URLs <- c("http://www.google.com", "http://www.stackoverflow.com")
ui <- fluidPage(
# set up shiny js to be able to call our browseURL function
useShinyjs(),
extendShinyjs(text = js_code, functions = 'browseURL'),
actionButton(
"click",
"Click here to open several browser tabs"
)
)
server <- function(input, output){
observeEvent(input$click, {
for (i in URLs){
js$browseURL(i)
Sys.sleep(1) #Short delay of 1 second
}
})
}
shinyApp(ui, server)