0

I am currently having troubles making my module UI and server communicating whith an intermediate renderUI creating the layout. Here is a repex with and without the dynamic creation of the tabsetPanel. I guess the problem comes from namespace but I cannot figure out where and how to fix it. DO NOT WORK :

mod_graphical_general_ui <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns("myselect"), "Select a choice", choices = NULL)
)}

mod_graphical_general_server <- function(id, choices = NULL) {
  moduleServer( id, function(input, output, session){
    ns <- session$ns
    updateSelectInput(session, "myselect", choices = choices)
    
  })
}

ui <- bootstrapPage(
  uiOutput("mytabs")
)

server <- function(input, output) {
  mod_graphical_general_server("mymodule", choices = c("aaa", "bbb"))
  
  output$mytabs = renderUI({
    number_of_tabs <- 3
    names_tab <- paste0("Tab", 1:number_of_tabs)
    myTabs = lapply(1: number_of_tabs, function(x) {tabPanel(names_tab[[x]], div(uiOutput(paste0("graphics_tab", x))))})
    do.call(tabsetPanel, c(myTabs))
  })
  
  output$graphics_tab1 <- renderUI({
    return(mod_graphical_general_ui("mymodule"))
  })
}

shinyApp(ui = ui, server = server)

If I remove the step from calling the tabsetPanel, the code works .

mod_graphical_general_ui <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns("myselect"), "Select a choice", choices = NULL)
)}

mod_graphical_general_server <- function(id, choices = NULL) {
  moduleServer( id, function(input, output, session){
    ns <- session$ns
    updateSelectInput(session, "myselect", choices = choices)
    
  })
}

ui <- bootstrapPage(
  #uiOutput("mytabs")
  uiOutput("graphics_tab1")
)

server <- function(input, output) {
  mod_graphical_general_server("mymodule", choices = c("aaa", "bbb"))
  
  output$mytabs = renderUI({
    number_of_tabs <- 3
    names_tab <- paste0("Tab", 1:number_of_tabs)
    myTabs = lapply(1: number_of_tabs, function(x) {tabPanel(names_tab[[x]], div(uiOutput(paste0("graphics_tab", x))))})
    do.call(tabsetPanel, c(myTabs))
  })
  
  output$graphics_tab1 <- renderUI({
    return(mod_graphical_general_ui("mymodule"))
  })
}

shinyApp(ui = ui, server = server)

I already have asked the question in the community rstudio but with no luck.

Bambs
  • 545
  • 4
  • 14

1 Answers1

0

Anyway, I fixed your code.

The thing is your mod server is run as the top-level shiny server starts. However, your mod UI is running later after the mod server. So this causes the updateSelectInput can't find the dynamic UI component to update. In your second example, the UI component is already there when app starts, so it doesn't have this issue.

We need to wait the render UI event is done when we can call the mod server. To understand this, you need to know how Shiny communicates with frontend javascript, not going into details here. You can read more on this issue.

mod_graphical_general_ui <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns("myselect"), "Select a choice", choices = NULL)
  )}

mod_graphical_general_server <- function(id, choices = NULL) {
  moduleServer(id, function(input, output, session){
    ns <- session$ns
    updateSelectInput(session, "myselect", choices = choices)
    
  })
}

ui <- bootstrapPage(
  uiOutput("mytabs")
)

server <- function(input, output, session) {
  output$mytabs = renderUI({
    number_of_tabs <- 3
    names_tab <- paste0("Tab", 1:number_of_tabs)
    myTabs = lapply(1:number_of_tabs, function(x) {tabPanel(names_tab[[x]], div(uiOutput(paste0("graphics_tab", x))))})
    do.call(tabsetPanel, c(myTabs))
  })
  
  output$graphics_tab1 <- renderUI({
    on.exit({
      observeEvent(once = TRUE, reactiveValuesToList(session$input), {
        mod_graphical_general_server("mymodule", choices = c("aaa", "bbb"))
      }, ignoreInit = TRUE)
    })
    return(mod_graphical_general_ui("mymodule"))
  })
}

shinyApp(ui = ui, server = server)

enter image description here

lz100
  • 6,990
  • 6
  • 29
  • Thanks, it worked perfectly as I wanted to. I added a complexity to the app and now the choices are stored in a reactiveValues. The code is not working anymore as the mod_graphical_general_server is evaluated only once. Any idea what could be the fix ? – Bambs May 13 '22 at 14:01
  • 1
    You can add another `observeEvent` inside your `mod_graphical_general_server` server to observe that `reactiveValues`. Once that has changed, update `myselect`. If `reactiveValues` is defined in top-level, pass it as an argument to `mod_graphical_general_server` – lz100 May 13 '22 at 19:36