Reputation: 3448
moduleServer
rather than callModule
.moduleServer
(unlike callModule
).moduleServer
, so that I can correctly reference the parent session in order for updateTabsetPanel
to work correctly inside a renderUI
dynamic output.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 tabPanel
s, 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
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