简体   繁体   中英

Using a reactive value and a reactive expression to trigger an observeEvent

The module in the app below contains an observer that has two triggers:

  1. a reactive value input$trigger1 (the value of a fileInput that is rendered inside the module server)
  2. a reactive expression trigger2() (the expression returns the value of an actionButton in the main app that is fed to the module).

I would like the observer to print some text to the console when triggered by changes in either of these two values.

Attempt 1: I tried wrapping the triggers in a vector:

  observeEvent(c(input$trigger1, trigger2()), print('the one with the vector'), ignoreInit = T)

Problem: This observeEvent fires when the checkbox is checked.

I thought this might have something to do with the module's server being called instantaneously on app start-up whereas the module's UI is only rendered if input$check == TRUE ? I tried investigating this by printing the values of input$trigger1 and trigger2() to the console using observe() . On start-up, the values printed to the console are trigger2(): 0 input$trigger1: NULL . When the checkbox is checked, input$trigger1 is still NULL but the observer fires again and prints input$trigger1: NULL to the console. Maybe this is due to trigger1 not existing in the DOM on start-up?

So I tried calling both the module's server and UI at the same time like so:

output$form = renderUI({req(input$check); modUI('mod')})

observeEvent(input$check, {
    req(input$check)
    callModule(modServer, 'mod', trigger2 = reactive(input$trigger2))
})

But the value of input$trigger1 still gets printed to the console twice, this time when the checkbox is checked. I don't know why because it's NULL on both occasions.


Attempt 2: According to a post in this thread it occurred to me that since input$trigger1 and trigger() have different classes, wrapping them in a vector might be the source of the problem (since R coerces them to the same class as pointed out by the linked post). So I tried using curly braces instead:

  observeEvent({input$trigger1; trigger2()}, print('the one with curly braces'), ignoreInit = T)

Problem: This observer responds to changes in trigger2() but not to changes in input$trigger1 . Maybe this has something to do with the return value of the eventExpr ( trigger2() ) not changing if input$trigger1 changes, but since the the eventExpr is a reactive expression, a change to either input$trigger1 or trigger2() should invalidate it to trigger the observer as in this post .


Attempt 3: I tried swapping the order of the triggers:

  observeEvent({trigger2(); input$trigger1}, print('the one with curly braces with the order swapped around'), ignoreInit = T)

Problem: This time the observer responds to both triggers but only if input$trigger1 is changed first. Otherwise, it is unresponsive.


Here is the reproducible code:

 library("shiny") # MODULE UI --------------------------------------------------------------- modUI = function(id) { ns = NS(id) uiOutput(ns('ui')) } # MODULE SERVER ----------------------------------------------------------- modServer = function(input, output, session, trigger2) { ns = session$ns output$ui = renderUI(fileInput(ns('trigger1'), 'Trigger1')) #OBSERVER 1 --------------------------------------------- observeEvent(c(input$trigger1, trigger2()), print('the one with the vector'), ignoreInit = T) # observe(print(list(`trigger2 (actionButton)` = trigger2()))) # observe(print(list(`trigger1 (fileInput)`= input$trigger1))) #OBSERVER 2 --------------------------------------------- # observeEvent({input$trigger1; trigger2()}, print('the one with curly braces'), ignoreInit = T) #OBSERVER 3 --------------------------------------------- # observeEvent({trigger2(); input$trigger1}, print('the one with curly braces with the order swapped around'), ignoreInit = T) } # MAIN APP ---------------------------------------------------------------- ui <- fluidPage( checkboxInput('check', 'Show'), uiOutput('form'), actionButton('trigger2', 'Trigger 2') ) server <- function(input, output, session) { output$form = renderUI({req(input$check); modUI('mod')}) # observe({ # req(input$check) # callModule(modServer, 'mod', trigger2 = reactive(input$trigger2)) # }) callModule(modServer, 'mod', trigger2 = reactive(input$trigger2)) } shinyApp(ui = ui, server = server)

I've tried everything I can think of to isolate the issue to no avail so any and all guidance would be very much appreciated.

UPDATE: Maybe it has something to do with the value of input$file being a data.frame ? I tried replacing input$trigger1 with trigger1() , a reactiveVal that increments by 1 each time input$trigger1 changes. This way both triggers have the same class and length (ie numeric(1)). The resulting observer works as expected:

modServer = function(input, output, session, trigger2) {

  ns = session$ns

  trigger1 = reactiveVal(0)

  observeEvent(input$trigger1, trigger1(trigger1()+1))

  observeEvent({trigger2(); trigger1()}, print('hello'), ignoreInit = T)

}

I would still like to understand why attempts 1-3 didn't work though so if anyone has any insight, please post a reply.


Explanation: As MattB pointed out, the actionButton initialises as 0 and the fileInput initialises as NULL. This means that the eventExpr for the observers in attempt 2 and 3 will evaluate to NULL as long as the input value on the last line of the expression is NULL. The eventExpr of the example in the linked post consists of a numericInput and a textInput. Since these initialise with values 0 and '' respectively, the eventExpr never returns NULL and the observer is always responsive to both inputs regardless of which is changed first.

observeEvent has ignoreNULL = TRUE set by default. As you correctly suspect, while the observer will trigger for a change to any part of {x;y} , it will only do that if the value of that whole expression is not NULL. In this example, as long as y is NULL, the observer won't trigger, no matter what you do to x . This is easily fixed by setting ignoreNULL = FALSE .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM