rshinyshinymodules

Why do we use session$ns in Shiny modules and not NS(id)?


Consider any Shiny module in which we use session$ns in the server part, e.g. the one below.

We could equivalently use NS(id) instead of session$ns. So why it is recommended to use session$ns? Is there an advantage over NS(id)?

library(shiny)

myModuleUI <- function(id){
  ns <- NS(id)
  uiOutput(ns("checkbox"))
}

myModuleServer <- function(id){
  moduleServer(id, function(input, output, session){
    ns <- session$ns
    output[["checkbox"]] <- renderUI({
      checkboxInput(ns("checkbox"), label = "Check me", value = FALSE)
    })
    observe({
      print(input[["checkbox"]])
    })
  })
}

ui <- basicPage(
  myModuleUI("myModule")
)

server <- function(input, output, session){
  myModuleServer("myModule")
}

shinyApp(ui, server)

Solution

  • Why?

    session$ns is mandatory if you want to use nested modules which use dynamic UI with uiOutput

    Minimal example

    library(shiny)
    ## NESTED MODULE
    nestedModuleUI <- function(id) {
      ns <- NS(id)
      uiOutput(ns("ui_out"))
    }
    
    nestedModuleServer <- function(id) {
      moduleServer(
        id,
        function(input, output, session) {
    
          output$ui_out <- renderUI({
            list(
              actionButton(session$ns("well_formed"), "I work"),
              actionButton(NS(id, "bad_formed"), "I do nothin'")
            )
          })
    
          observeEvent(input$well_formed,  print("button pressed!"))
          observeEvent(input$bad_formed,  print("button pressed!"))
        }
      )
    }
    
    ## CONTAINER MODULE
    containerModuleUI <- function(id) {
      ns <- NS(id)
      nestedModuleUI(ns("nested"))
    }
    
    containerModuleServer <- function(id) {
      moduleServer(
        id,
        function(input, output, session) {
          nestedModuleServer("nested")
        }
      )
    }
    
    ## Application
    ui <-  containerModuleUI("container")
    
    server <- function(input, output, session) containerModuleServer("container")
    
    shinyApp(ui, server)
    
    

    see also this answer