Search code examples
rshinyshinymodules

renderUI in a modal inside nested shiny modules


Say I have my module1 below which shows a modal when the button is clicked. It works fine.

library(shiny)

module1_ui <- function(id) {
  shiny::tagList(
    actionButton(
      inputId = NS(namespace = id, id = "actbtn"), 
      label = "Click"
    )
  )
}

module1_server <- function(id, input_data) {
  stopifnot(is.reactive(input_data))
  
  moduleServer(
    id = id, 
    
    module = function(input, output, session) {
      # modal:
      modal_1 <- function() {
        modalDialog(
          title = "Modal Dialog", 
          footer = NULL, 
          easyClose = TRUE, 
          size = "l", 
          
          shiny::tagList(
            tags$h3(
              "I am a modal!"
            ), 
            
            uiOutput(outputId = NS(namespace = id, id = "rendered"))
          )
        )
      }
      
      output$rendered <- renderUI({
        shiny::tagList(
          tags$h1("And this is my rendered text")
        )
      })
      
      # show modal on btn click:
      observeEvent(input$actbtn, {
        showModal(
          modal_1()
        )
      })
    }
  )
}

ui <- fluidPage(
  module1_ui(id = "module1")
)

server <- function(input, output, session) {
  module1_server(
    id = "module1", 
    input_data = reactive({ })
  )
}

shinyApp(ui, server)

But if I nest module1 in another module2 the rendered text doesn't show:

module2_ui <- function(id) {
  shiny::tagList(
    module1_ui(id = NS(namespace = id, id = "module1"))
  )
}

module2_server <- function(id, input_data) {
  stopifnot(is.reactive(input_data))
  
  moduleServer(
    id = id, 
    
    module = function(input, output, session) {
      module1_server(
        id = "module1", 
        input_data = input_data
      )
    }
  )
}

ui <- fluidPage(
  module2_ui(id = "module2")
)

server <- function(input, output, session) {
  module2_server(
    id = "module2", 
    input_data = reactive({ iris })
  )
}

shinyApp(ui, server)

What am I missing? It maybe an issue to do with namespacing but I can't figure it out.

Help!


Solution

  • Try this

    library(shiny)
    
    module1_ui <- function(id) {
      shiny::tagList(
        actionButton(
          inputId = NS(namespace = id, id = "actbtn"), 
          label = "Click"
        )
      )
    }
    
    module1_server <- function(id, input_data) {
      stopifnot(is.reactive(input_data))
      
      moduleServer(
        id = id, 
        
        module = function(input, output, session) {
          # modal:
          ns <- session$ns
          modal_1 <- function() {
            modalDialog(
              title = "Modal Dialog", 
              footer = NULL, 
              easyClose = TRUE, 
              size = "l", 
              
              shiny::tagList(
                tags$h3(
                  "I am a modal!"
                ), 
                
                uiOutput(outputId = ns("rendered"))
              )
            )
          }
          
          output$rendered <- renderUI({
            shiny::tagList(
              tags$h1("And this is my rendered text")
            )
          })
          
          # show modal on btn click:
          observeEvent(input$actbtn, {
            showModal(
              modal_1()
            )
          })
        }
      )
    }
    
    module2_ui <- function(id) {
      ns <- NS(id)
      shiny::tagList(
        module1_ui(id = ns("module1"))
      )
    }
    
    module2_server <- function(id, input_data) {
      stopifnot(is.reactive(input_data))
      
      moduleServer(
        id = id, 
        
        module = function(input, output, session) {
          module1_server(
            id = "module1", 
            input_data = input_data
          )
        }
      )
    }
    
    ui <- fluidPage(
      module2_ui(id = "module2")
    )
    
    server <- function(input, output, session) {
      module2_server(
        id = "module2", 
        input_data = reactive({ iris })
      )
    }
    
    shinyApp(ui, server)