5

I would like to know in the example below which event is fired in the multiple ObserveEvent().

ui <- fluidPage(
  numericInput("a", "a", 0),
  textInput("b", "b")
)

server <- function(input, output, session) {
  observeEvent({
    input$a
    input$b
  },{

    # If only input$a is fired, I want to know that is input$a

  })
}

shinyApp(ui, server)

Or the only solution is to have two ObserveEvent() like the second link ? like that ?

ui <- fluidPage(
  numericInput("a", "a", 0),
  textInput("b", "b")
)

server <- function(input, output, session) {
  observeEvent({
    input$a
  },{

    my_function_or_reactive_function(input,1)

  })

  observeEvent({
    input$b
  },{

    my_function_or_reactive_function(input,2)

  })

}

shinyApp(ui, server)

link:

phili_b
  • 885
  • 9
  • 27

1 Answers1

10

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

library(shiny)

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)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
  • Thank you very much: ) I'm surprised that this functionality doesn't exist by default in `observeEvent()`. – phili_b Jun 26 '19 at 12:05
  • 1
    You are welcome! Yes, it would definitely make a nice convenience feature. You could propose it [here](https://github.com/rstudio/shiny/issues). Maybe they are interested. – ismirsehregal Jun 26 '19 at 12:12
  • I have a problem. If I add `textInput("c", "c")`, when I trigger `c` then `observeEvent(c(input$a,input$b),` catches `.clientdata_output_changedInputs_hidden` and `c` also. – phili_b Jun 26 '19 at 13:13
  • and without `Shiny.setInputValue()` `observeEvent(c(input$a,input$b),` catches only `a` and `b`. – phili_b Jun 26 '19 at 13:16
  • Currently the JS code catches all changed inputs, thats why I used `if (input$changed == "a")` inside the observer to react only when `input$a` was changed. You could also adapt the JS code to only listen on changes of `input$a` by using `event.name == 'a'` but that's less flexible. – ismirsehregal Jun 26 '19 at 13:23
  • Just updated my answer to show it more clearly. The observer only reacts to `a` and `b`. You were probably looking at the text output which is rendered outside the observer. – ismirsehregal Jun 26 '19 at 13:41
  • no no. I don't agree with your 13:23 answer. :) I will not use `Shiny.setInputValue()` in this case. But in your initial answer it works but `renderText()` return "outside the observer"(13:41). In fact it is in my real app that I have reactive consequences with [Addressing multiple inputs in shiny](https://stackoverflow.com/questions/40044768/addressing-multiple-inputs-in-shiny/40045292#40045292) and maybe `Shiny.setInputValue()`. Could you remove your last answer and put your initial answer, please :) – phili_b Jun 26 '19 at 13:58
  • Added a gif to show that when adding `input$c` it is not interfering with the `observeEvent(c(input$a,input$b)`. – ismirsehregal Jun 26 '19 at 14:31
  • 1
    ha :) I was doing the same in your code because you initial render outside observer was confusing. Thank you :) – phili_b Jun 26 '19 at 14:47
  • My new question :) with `grep()` and `setInputValue()`. [Get the event which is fired in Shiny and with grep (generated input)](https://stackoverflow.com/questions/56776207/get-the-event-which-is-fired-in-shiny-and-with-grep-generated-input) – phili_b Jun 26 '19 at 15:24
  • @ismirsehregal This works on the usual input elements standing alone (such as ```textInput```, ```numericInput```). How do I modify this to work for these same elements embedded in an ```uiOutput``` element which embeds many of such individual input elements? In such a case, ```input$changed``` does not produce the name of the fired input, but the name of the ```uiOutput``` element and the action on that element, like this ```sample_table_cell_click```, where ```sample_table``` is my ```uiOutput``` element. – Tristan Tran Sep 14 '20 at 19:23
  • 3
    @TristanTran please see my edit. It's working fine also with `renderUI`. However, if you still have problems with your special case, try to create a simple example and post it as a new question. – ismirsehregal Sep 15 '20 at 13:57