Get the Event Which Is Fired in Shiny

Get the event which is fired in Shiny?

You can use shiny's JS event shiny:inputchanged to check which input changed:

ui <- fluidPage(
tags$head(
tags$script(
"$(document).on('shiny:inputchanged', function(event) {
if (event.name != 'changed') {
Shiny.setInputValue('changed', event.name);
}
});"
)
),
numericInput("a", "a", 0),
textInput("b", "b"),
textInput("c", "c"),
textOutput("changedInputs"),
textOutput("aFired")
)

server <- function(input, output, session) {
output$changedInputs <- renderText({
paste("Outside observer: Latest input fired:", paste(input$changed, collapse = ", "))
})

observeEvent({
c(input$a,
input$b)
}, {
req(input$changed)
if (input$changed == "a") {
output$aFired <- renderText("Inside observer: input$a was fired")
} else if (input$changed == "b") {
output$aFired <- renderText("Inside observer: input$b was fired")
} else if (input$changed == "c") {
output$aFired <- renderText("Inside observer: input$c was fired")
}
}, ignoreInit = TRUE)
}

shinyApp(ui, server)

Result:

Edit - request from @TristanTran using renderUI:

library(shiny)

ui <- fluidPage(
tags$head(
tags$script(
"$(document).on('shiny:inputchanged', function(event) {
if (event.name != 'changed') {
Shiny.setInputValue('changed', event.name);
}
});"
)
),
uiOutput("serverside"),
textOutput("changedInputs"),
textOutput("aFired")
)

server <- function(input, output, session) {
output$changedInputs <- renderText({
paste("Outside observer: Latest input fired:", paste(input$changed, collapse = ", "))
})

output$serverside <- renderUI({
tagList(
numericInput("a", "a", 0),
textInput("b", "b"),
textInput("c", "c")
)
})

observeEvent({
c(input$a,
input$b)
}, {
req(input$changed)
if (input$changed == "a") {
output$aFired <- renderText("Inside observer: input$a was fired")
} else if (input$changed == "b") {
output$aFired <- renderText("Inside observer: input$b was fired")
} else if (input$changed == "c") {
output$aFired <- renderText("Inside observer: input$c was fired")
}
}, ignoreInit = TRUE)
}

shinyApp(ui, server)

Get the event which is fired in Shiny and with grep (generated input)

There were two problems that needed to be addressed:

  1. your regular expression |c caught input$changed
  2. you need to use isolate(names(input)) inside the event expression otherwise the observer will fire for every change of names(input)
  3. Edit: use isolate({input$changed}) - see comments (not needed when using reactiveVal())

ui <- fluidPage(
tags$head(
tags$script(
"$(document).on('shiny:inputchanged', function(event) {
if (event.name != 'changed') {
Shiny.setInputValue('changed', event.name);
}
});"
)
),
numericInput("a_1", "a_1", 0),
textInput("a_2", "a_2"),
textInput("c", "c"),
textInput("d", "d"),

p("changedInputs:"), textOutput("changedInputs"), br(),
p("aFired:"), textOutput("aFired")
)

server <- function(input, output, session) {
output$changedInputs <- renderText({
paste("Outside observer: Latest input fired:", paste(input$changed, collapse = ", "))
})

observeEvent(eventExpr = {
lapply(grep(pattern = "^a_+[[:digit:]]$|^c$", x = isolate({names(input)}), value = TRUE), function(x){input[[x]]})
}, handlerExpr = {
req(input$changed)
if (input$changed == "a_1") {
output$aFired <- renderText("Inside observer: input$a_1 was fired")
} else if (input$changed == "a_2") {
output$aFired <- renderText("Inside observer: input$a_2 was fired")
} else {
output$aFired <- renderText({paste("Inside observer:", isolate({input$changed}), "was fired")})
}
}, ignoreInit = TRUE)
}

shinyApp(ui, server)

Another Edit: Now I remember where the isolate({input$changed}) got lost (I was sure it worked during my tests...) Initially I suspected the renderText() nested inside the observer might cause the problems, accordingly I implemented a reactiveVal() to print the output. This solution works without isolate({input$changed}):

ui <- fluidPage(
tags$head(
tags$script(
"$(document).on('shiny:inputchanged', function(event) {
if (event.name != 'changed') {
Shiny.setInputValue('changed', event.name);
}
});"
)
),
numericInput("a_1", "a_1", 0),
textInput("a_2", "a_2"),
textInput("c", "c"),
textInput("d", "d"),

p("changedInputs:"), textOutput("changedInputs"), br(),
p("aFired:"), textOutput("aFired")
)

server <- function(input, output, session) {
output$changedInputs <- renderText({
paste("Outside observer: Latest input fired:", paste(input$changed, collapse = ", "))
})

myText <- reactiveVal()

observeEvent(eventExpr = {
lapply(grep(pattern = "^a_+[[:digit:]]$|^c$", x = isolate({names(input)}), value = TRUE), function(x){input[[x]]})
}, handlerExpr = {
req(input$changed)
if (input$changed == "a_1") {
myText("Inside observer: input$a_1 was fired")
} else if (input$changed == "a_2") {
myText("Inside observer: input$a_2 was fired")
} else {
myText(paste("Inside observer:", input$changed, "was fired"))
}
}, ignoreInit = TRUE)

output$aFired <- renderText({myText()})

}

shinyApp(ui, server)

After finding out about the actual problems and before posting my answer here I reverted back to the version without reactiveVal() (since it is closer to your question) and forgot the isolate. Accordingly you received a mixture of both versions in the first place.

Take action when any of the button is clicked Shiny R

Use observeEvent instead and put all your triggers in c()

library(shiny)

ui <- fluidPage(
actionButton('button1', 'button1'),actionButton('button2', 'button2'),actionButton('button3', 'button3'))
server <- function(input, output, session) {
observeEvent(c(input$button1, input$button2, input$button3), ignoreInit = TRUE, {
showNotification("This is a notification.")
})
}

shinyApp(ui, server)

How to listen for more than one event expression within a Shiny eventReactive handler

I know this is old, but I had the same question. I finally figured it out. You include an expression in braces and simply list the events / reactive objects. My (unsubstantiated) guess is that shiny simply performs the same reactive pointer analysis to this expression block as to a standard reactive block.

observeEvent({ 
input$spec_button
mainplot.click$click
1
}, { ... } )

EDIT

Updated to handle the case where the last line in the expression returns NULL. Simply return a constant value.

Shiny observeEvent shows first event, but not second, third

There are a couple of issues with your code:

  1. renderText won't refire if you press input$go again (w/o changing the slider). Becasue the idea is that observer/render fires whenever their reactives change. As your renderText depends on rv$time which does not change when input$time does not change, the render function is not fired on subsequent button presses. This can be remedied by including input$go in the render function setting an additional dependency on the button.
  2. This will not, however, solve your problem, because the browser uses caching. It sees that the <img> tag did not change (same src), thus it does not reload the picture. To circumvent that you can use the trick from Disable cache for some images by adding a timestamp to the src.

To make a long story short, this code does the trick:

output$simple_timer <- renderText({
input$go # make code dependent on the button
# add `?timestamp=<timestamp>`to the src URL to convince the browser to reload the pic
glue::glue('<img src ="https://github.com/matthewhirschey/time_timer/raw/main/data/{rv$time}_sec.gif?timestamp={Sys.time()}",
align = "center",
height="50%",
width="50%">')
})


Related Topics



Leave a reply



Submit