Module returning before all inputs have updated

62 views Asked by At

I currently have a module that has three user inputs, which dynamically update depending on a dataset so people can't choose options that don't exist. These inputs then get taken to the main server for use in graphs/tables etc.

My problem is that server.R is receiving updates when inputs are changed too quickly and it's not waiting for all the inputs to update (since choice 3 depends on choice 2 and choice 2 depends on choice 1).

My initial options are:

"Choice 1:" "1"
"Choice 2:" "a"
"Choice 3:" "A ONLY 1"

If i change choice 2 to "b" I get the following in console:

"Choice 1:" "1"
"Choice 2:" "b"
"Choice 3:" "A ONLY 1"

"Choice 1:" "1"
"Choice 2:" "b"
"Choice 3:" "B ONLY 1"

Choice 3 hasn't updated quickly enough which will cause errors throughout my. Any idea how I can get the user_inputs in server.R to wait for all choices to finished updating?

Example code:

    test_data <- data.frame(matrix(c(
      1,"a","A ONLY 1",
      1,"a","A ONLY 1",
      1,"b","B ONLY 1",
      1,"b","B ONLY 2",
      2,"d","D ONLY 1"),byrow = TRUE,ncol = 3))
    names(test_data) <- c("choice1","choice2","choice3")
    
    
    module_inputs_ui <- function(id) {
      ns <- NS(id)
      
      shiny::fluidPage(  
            shiny::selectizeInput(
              label = "1",
              inputId = ns("choose1"),
              choices = c(1,2)
              ),
            selectInput(
              label = "2",
              inputId = ns("choose2"),
              choices = c("a","b")
              ),
            selectInput(
              label = "3",
              inputId = ns("choose3"),
              choices = c("x","y")
            )
      )
      
    }
    
    
    
    module_inputs_server <- function(id) {
      
      moduleServer(id, 
                   function(input, output, session) {
     
                     choice_2_new <- reactive({
                       test_data %>%
                         filter(choice1 == input$choose1) %>%
                         pull(choice2) %>%
                         unique()
                     })
                     
    
                     choice_3_new <- reactive({
                       test_data %>%
                         filter(choice1 == input$choose1) %>%
                         filter(choice2 == input$choose2) %>%
                         pull(choice3) %>%
                         unique()
                     })
                     
                     observeEvent(input$choose1, {
                       
                       updateSelectInput(
                         session = session,
                         inputId = "choose2",
                         choices = choice_2_new()
                       ) 
    
                       
                     })   
                     
                     
                     observeEvent(input$choose2, {
       
                       
                       updateSelectInput(
                         session = session,
                         inputId = "choose3",
                         choices = choice_3_new()
                       ) 
                       
                       
                     })   
                     # Return List -------------------------------------------------------------
    
                     return(
                       list(
                         out1 = reactive({input$choose1}),
                         out2 = reactive({input$choose2}),
                         out3 = reactive({input$choose3})
                       )
                       )
    
                   })
      
    }
    
    ui <- shiny::fluidPage(
      module_inputs_ui(id = "module_1")
    )
    
    
    server <- function(input, output, session) {
      
      user_inputs <- module_inputs_server(id = "module_1")  
    
      # # Printing inputs from user (for debuggins etc.)
      observe({
        
        print(c("Choice 1:", user_inputs$out1()))
        
        print(c("Choice 2:", user_inputs$out2()))
        
        print(c("Choice 3:", user_inputs$out3()))
    
        
      })
      
    }
    
    
    shinyApp(ui = ui, server = server)
1

There are 1 answers

9
YBS On

As the second observer depends on choice_3_new, you should observe on that. Then it works fine. Try this

test_data <- data.frame(matrix(c(
  1,"a","A ONLY 1",
  2,"a","A ONLY 2",
  1,"b","B ONLY 1",
  2,"b","B ONLY 2",
  2,"d","D ONLY 1"),byrow = TRUE,ncol = 3))
names(test_data) <- c("choice1","choice2","choice3")

module_inputs_ui <- function(id) {
  ns <- NS(id)
  
  shiny::fluidPage(  
    shiny::selectizeInput(
      label = "1",
      inputId = ns("choose1"),
      choices = c(1,2)
    ),
    selectInput(
      label = "2",
      inputId = ns("choose2"),
      choices = c("a","b")
    ),
    selectInput(
      label = "3",
      inputId = ns("choose3"),
      choices = c("x","y")
    )
  )
  
}

module_inputs_server <- function(id) {
  
  moduleServer(id, 
               function(input, output, session) {
                 
                 choice_2_new <- reactive({
                   test_data %>%
                     filter(choice1 == input$choose1) %>%
                     pull(choice2) %>%
                     unique()
                 })
                 
                 
                 choice_3_new <- reactive({
                   test_data %>%
                     filter(choice1 == input$choose1) %>%
                     filter(choice2 == input$choose2) %>%
                     pull(choice3) %>%
                     unique()
                 })
                 
                 observeEvent(input$choose1, {
                   req(choice_2_new())
                   updateSelectInput(
                     session = session,
                     inputId = "choose2",
                     choices = choice_2_new()
                   ) 
                 })   
                 
                 
                 observeEvent(choice_3_new(), {
                   updateSelectInput(
                     session = session,
                     inputId = "choose3",
                     choices = choice_3_new()
                   ) 
                 })   
                 # Return List -------------------------------------------------------------
                 
                 return(
                   list(
                     out1 = reactive({input$choose1}),
                     out2 = reactive({input$choose2}),
                     out3 = reactive({input$choose3})
                   )
                 )
                 
               })
  
}

ui <- shiny::fluidPage(
  module_inputs_ui(id = "module_1")
)


server <- function(input, output, session) {
  
  user_inputs <- module_inputs_server(id = "module_1")  
  
  # # Printing inputs from user (for debuggins etc.)
  observe({
    
    print(c("Choice 1:", user_inputs$out1()))
    
    print(c("Choice 2:", user_inputs$out2()))
    
    print(c("Choice 3:", user_inputs$out3()))
    
    
  })
  
}


shinyApp(ui = ui, server = server)