shinyshiny-reactivityshinymodules

initiate observeEvent() inside a module using an external button (or other trigger)


I have reviewed every post I can find about observeEvent(), updateSelectInput(), and module communication, and have yet to find an answer. What am I missing?

I want to be able to reset multiple user input widgets using a single button. Each user input widget is its own module. I'm using modules for the user inputs because I have a large app with multiple data tables that each need different filters that take user input. I do NOT want to include a reset button for each input widget because there are too many of them and it would crowd the app way too much. I want to be able to do this with just the basic library(shiny), not by adding even more extra packages. shiny.js supposedly has a way to do this more easily but I couldn't get that to work either, and it really seems like it shouldn't be necessary.

Here is a simple, reproducible example:

library(shiny)

#simple version of a filter module I'm using - the point is that I need to be able to use a single button to update multiple filter modules
selectinput_UI <- function(id) {
  ns <- NS(id)
  
  tagList(
    selectInput(inputId = ns("select_input"),
                label = "Input",
                choices = c("choice1", "choice2", "choice3", "choice4"),
                selected = "choice2"),
    verbatimTextOutput(outputId = ns("user_output")),
    verbatimTextOutput(outputId = ns("button_clicks")) #demonstrates that the button is, in fact, clicking, even within the module)
  )
}

#server-side for the filter module - includes an input for the reactive value of the outer button
selectinput_server <- function(id, reset) {
  moduleServer(
    id,
    function(input, output, session) {
      ns <- session$ns
      
      output$user_output <- renderText({input$select_input})
      
      output$button_clicks <- renderText({reset()})
      
      #observeEvent SHOULD trigger any time the eventExpr changes
      observeEvent(reset(), {
        updateSelectInput(session = session,
                          inputId = ns("select_input"),
                          selected = "choice3")
      })
      
    }
  )
}

ui <- fluidPage(
  selectinput_UI(id = "test"),
  actionButton(inputId = "button",
               label = "Reset")

)

server <- function (input, output, session) {
  
  click <- reactive({input$button})
  
  selectinput_server(id = "test", reset = click)
}

shinyApp(ui = ui, server = server)

I've tried many approaches, the simple example I've provided is the most promising I think, but it still doesn't work, and I don't understand why. It doesn't throw any errors, the button clicks, selectInput() seems to work fine, but the value does not update like it should when the button is clicked. Is something wrong with how I've done the updateSelectInput()? Ideas? Thoughts? Am I missing something obvious?

Also open to other ideas about how to approach my end goal of having a single button that resets a series of individual filters that are each their own module.

Others with similar types of issues are lacking the ns() on the server-side, but that's clearly not my problem here.

This is the closest thing I've seen to what I'm trying to do: Modularizing R Shiny code: ObserveEvent function in module But still doesn't change anything.


Solution

  • You were almost there. You have an extra call to ns. Change the updateSelectInput to this:

    updateSelectInput(
      session = session,
      inputId = "select_input",
      selected = "choice3"
    )
    

    There's no need to call ns on the inputId since you have specified the session parameter.