Shiny App: Nothing Changes When Clicking on Action Button

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$Buttonin 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



Leave a reply



Submit