heds1
heds1

Reputation: 3448

Passing additional parameters to moduleServer in R Shiny app: accessing parent environment for updateTabsetPanel

This post demonstrates how to use callModule to pass the parent session into the module so that updateTabsetPanel can reference the parent session and update it accordingly. I used that approach to create a minimal example here. There are two tabPanels, and we are trying to navigate to the second via an actionLink in the first. The first_server module is called with callModule, and we are able to pass the parent session parameter as an additional argument, allowing us to reference it in the updateTabsetPanel call in first_server. Clicking the actionLink then takes us to the second module UI, as expected:

library(shiny)

first_ui <- function(id) {
    ns <- NS(id)
    uiOutput(ns("goto_second_link_ui"))
}

second_ui <- function(id) {
    ns <- NS(id)
    p("It worked!")
}

first_server <- function(input, output, session, parent) {
    output$goto_second_link_ui <- renderUI({
        actionLink(session$ns("goto_second"), label = "Go to second module")
    })
    observeEvent(input$goto_second, {
        updateTabsetPanel(parent,
            inputId = "main",
            selected = "second"
        )
    })
}

ui <- {
    fluidPage(
        tabsetPanel(id = "main",
            tabPanel(value = "first",
                title = "First module",
                first_ui("first")    
            ),
            tabPanel(value = "second",
                title = "Second module",
                second_ui("second")    
            )
        )
    )
}

server <- function(input, output, session) {
    callModule(first_server, id = "first", parent = session)
}

shinyApp(ui, server)

I've tried a couple of approaches to get this to work with moduleServer. The best guess I had was to pass the parent session all the way through to the module argument of moduleServer (relevant changes only shown):

first_server <- function(id, parent) {
    moduleServer(id, function(input, output, session, parent = parent) {
        output$goto_second_link_ui <- renderUI({
            actionLink(session$ns("goto_second"), label = "Go to second module")
        })
        observeEvent(input$goto_second, {
            updateTabsetPanel(parent,
                inputId = "main",
                selected = "second"
            )
        })
    })
}

server <- function(input, output, session) {
    first_server("first", parent = session)
}

This generates an error when I click the actionLink that I don't fully understand:

Warning: Error in updateTabsetPanel: promise already under evaluation: recursive default argument reference or earlier problems?

Thanks for reading and any suggestions.

Upvotes: 10

Views: 1283

Answers (1)

YBS
YBS

Reputation: 21349

Once you remove the extra argument in moduleServer it works. Try this

library(shiny)

first_ui <- function(id) {
  ns <- NS(id)
  uiOutput(ns("goto_second_link_ui"))
}

second_ui <- function(id) {
  ns <- NS(id)
  p("It worked!")
}

first_server <- function(id,parent) {
  moduleServer(id, function(input, output, session) {
    ns <- session$ns
    output$goto_second_link_ui <- renderUI({
      actionLink(ns("goto_second"), label = "Go to second module")
    })
    observeEvent(input$goto_second, {
      updateTabsetPanel(parent,
                        inputId = "main",
                        selected = "second"
      )
    })
  })
}

ui <- {
  fluidPage(
    tabsetPanel(id = "main",
                tabPanel(value = "first",
                         title = "First module",
                         first_ui("first")    
                ),
                tabPanel(value = "second",
                         title = "Second module",
                         second_ui("second")    
                )
    )
  )
}

server <- function(input, output, session) {
  first_server("first", parent = session)
}

shinyApp(ui, server)

Upvotes: 10

Related Questions