Shiny app does not react on action button
The problem was the second uiOutput('my_output')
in ui
. Removing it brings back reactivity.
Note: I am sharing this Q&A-style because it took me one hour to figure it out in my real app. It is way longer and messier than the MRE above, so the fact that I had the same output twice was not obvious (they were on different tabs, moreover). Plus, I did not even know that displaying the same output in more than one place in the app was forbidden.
Finally, the complete silence (no error or warning whatsoever) did not help.
I hope it can save other people in my situation some time!
Only activate actionButton when Shiny app is not busy
You can disable button after it is clicked and enable it again on exit. It can be done manually but shinyjs
already provides required helpers.
If function called on click may fail you can use tryCatch
with finally
to make sure that your app won't stay in the disabled state:
library(shiny)
library(shinyjs)
foo <- function() {
Sys.sleep(4)
x <- runif(1)
if(x < 0.5) stop("Fatal error")
print(x)
}
shinyApp(
ui=shinyUI(bootstrapPage(
useShinyjs(),
actionButton("go", "GO")
)),
server=shinyServer(function(input, output, session){
observe({
if(input$go == 0) return()
shinyjs::disable("go")
tryCatch(
foo(),
error = function(e) return(),
finally = shinyjs::enable("go")
)
})
})
)
Why doesn't my Shiny (R) actionButton respond after I use a different actionLink?
That happens because of the output$delError<<-renderText({""})
code that overwrites the original output$delError
expression by the empty one, so no surprise output$delError
does not trigger on input$delButton
any more.
[UPDATE]
The OP's application uses actionButton
and actionLink
to delete and undelete records from a database, respectively. The 'delete' button is supposed to trigger the delError
expression that deletes the record and shows the outcome of deletion (e.g. 'record deleted'). Similarly, the 'undelete' button triggers the undoError
expression that puts the record back into the table and reports an outcome of undeletion (e.g. 'record undeleted'). The problem is that undoError
has to get rid of the output produced by delError
because outputs 'record deleted' and 'record undeleted' don't make much sense when they appear together, but the output 'record deleted' can be removed only by the delError
expression.
It seems that this problem can be resolved by modifying delError
to make it hide its output when the 'undelete' button (or link) is pressed. But in this case, delError
would trigger on both 'delete' and 'undelete' buttons without being able to say which button caused the evaluation, so it would try to delete a record when the 'undelete' button is pressed!
The sample application below provides a way to address this problem by using a global variable that stores the status of the last operation. This status is generated by two high-priority observers (one for 'delete' and another for 'undelete'), which also take care of actual deleting/undeleting of the record. The observers don't produce output that directly goes to the web page, so there is no hassle with getting rid of the messages produced by the other observer. Instead, the status variable is shown by a simple reactive expression.
server.R
tempEntry<-NULL
dat<-data.frame(nums=1:3,ltrs=c("a","b","c"))
shinyServer(function(input, output, session) {
del.status <- NULL
##################
### Observers ####
##################
delete.row <- observe({
if (input$delButton ==0 ) return() # we don't want to delete anything at start
delNum <- isolate( input$delNum ) # this is the only thing that needs to be isolated
if (is.na(delNum)) {
print('nope2')
return()
}
tempEntry <<- dat[delNum,]
dat <<- dat[-delNum,]
output$undo <<- renderUI( actionLink("undo","Undo last delete") )
del.status <<- 'deleted'
},priority=100) # make sure that del.status will be updated *before* the evaluation of output$delError
undelete.row <- observe({
if (is.null(input$undo) || input$undo==0) return() # trigger on undowe don't want to undelete anything at the beginning of the script
dat <<- rbind(dat,tempEntry)
tempEntry <<- NULL
output$undo <<- renderUI("")
del.status <<- 'undeleted'
},priority=100)
##################
### Renderers ####
##################
output$delError <- renderText({
if (input$delButton == 0) return() # show nothing until first deletion
input$undo # trigger on undo
return(del.status)
})
output$show.table <- renderTable({
input$delButton; input$undo # trigger on delete/undelete buttons
return(dat)
})
})
ui.R
library(shiny)
shinyUI(
navbarPage(
"example"
, tabPanel("moo"
, titlePanel("")
, fluidPage(
numericInput("delNum","Row to delete",value=NULL)
, div(p(textOutput("delError")),style="color:red")
, actionButton("delButton","Delete row")
, uiOutput("undo")
, tableOutput('show.table')
)
)
)
)
Shiny crashes when Run button is clicked - but only when starting in a certain tab
When objects are not visible on the page they are suspended (not executed) by default in shiny. Thus, you'll get an error when you try to use the output that is generated on any of the tabs you haven't opened yet. You can get around this with outputOptions
see the reference here. Note the following:
suspendWhenHidden. When TRUE (the default), the output object will be suspended (not execute) when it is hidden on the web page. When FALSE, the output object will not suspend when hidden, and if it was already hidden and suspended, then it will resume immediately.
Basically the 4 tabs that are not on the screen are suspended and will not be rendered until you click on them. This explains why when you click on them and go back you don't see the same error. Add a line similar to this one at the bottom of your server script for each of the tabs you need rendered:
outputOptions(output, "Ratings", suspendWhenHidden = FALSE)
Update content on server only after I click action button in Shiny
submitButton
is just made for this.
If you want to use actionButton
instead, simply use isolate
to avoid refresh based on value changes, and add the input$Button
in the code like:
output$Minimal_Example <- renderPrint({
input$Button
Age <- isolate(input$Age)
Sex <- isolate(input$ChosenSex)
c(Age, Sex)
})
Shiny R Session Aborted when pressing actionButton
Solved: Was a "variable naming" problem. And after finding that, I realized the button wasn't needed in the webapp. Thank you all
Related Topics
Ggplot: How to Increase Spacing Between Faceted Plots
Convert a Row of a Data Frame to Vector
How to Make a Matrix from a List of Vectors in R
Compare Two Character Vectors in R
Get the Path of Current Script
Here We Go Again: Append an Element to a List in R
Coding Practice in R:What Are the Advantages and Disadvantages of Different Styles
Reorder Rows Using Custom Order
Avoid Wasting Space When Placing Multiple Aligned Plots Onto One Page
How to Increase the Size of Points in Legend of Ggplot2
What Is a Good Way to Read Line-By-Line in R
Recommended Package for Very Large Dataset Processing and MAChine Learning in R
Given a Set of Random Numbers Drawn from a Continuous Univariate Distribution, Find the Distribution
Can't Change Fonts in Ggplot/Geom_Text
Easier Way to Plot the Cumulative Frequency Distribution in Ggplot