Search code examples
rshinyshinymodules

shiny module namespace issue with dynamic creation of tabesetPanel


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.


Solution

  • 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