I am trying to convert a section of code into a Shiny Module, but my renderPlot()
functions generated within an lapply()
don't seem to be working. I have created a simple example below to demonstrate the issue.
(Note: Here I'm using renderText()
calls, but the same behavior applies.)
app_normal.R:
library(shiny)
ui <- fixedPage(
h2("Normal example"),
uiOutput("test")
)
server <- function(input, output, session) {
output$test <- renderUI({
lapply(1:3, function(val) {
fluidRow(column(12,renderText(paste("Line", val))))
})
})
}
shinyApp(ui, server)
app_module.R:
library(shiny)
myModuleUI <- function(id) {
ns <- NS(id)
uiOutput(ns("test"))
}
myModule <- function(input, output, session) {
output$test <- renderUI({
lapply(1:3, function(val) {
fluidRow(column(12,renderText(paste("Line", val))))
})
})
}
ui <- fixedPage(
h2("Module example"),
myModuleUI("test_module")
)
server <- function(input, output, session) {
callModule(myModule, "test_module")
}
shinyApp(ui, server)
All of the div
elements are being created, but they just fail to contain the plots/text. How do I properly use the Shiny renderText()
or renderPlot()
functions within renderUI()
/lapply()
calls within a module?
It appears that the approach I was taking using the renderText()
and renderPlot()
functions directly in a renderUI()
works fine in the normal case, i.e. when not operating within a Shiny Module. Shiny automatically calls the necessary textOutput()
or plotOutput()
to generate the HTML. Some how this automatic link is broken when you are performing the same operations within a Shiny Module. I suspect this is due to the mismatch between assigning and referencing items in the output
list due to the introduction of the ns()
call when assigning outputId
s as is done manually in a call to outputPlot()
or outputText()
.
To successfully use renderUI
within a Shiny Module, you need to separately call textOutput()
and renderText()
: textOutput
in the lapply()
in the renderUI()
, and renderText()
in an lapply()
in an observe()
. This allows us to introduce an ns()
into the generation of the outputId
for the textOutput()
call.
Below I've included a refactoring of both app_normal.R
and app_module.R
that demonstrates the disentanglement of these two calls.
app_normal_observe.R:
library(shiny)
ui <- fixedPage(
h2("Normal example"),
uiOutput("test")
)
server <- function(input, output, session) {
output$test <- renderUI({
lapply(1:3, function(val) {
fluidRow(column(12,textOutput(paste0("line_", val))))
})
})
observe({
lapply(1:3, function(val) {
output[[paste0("line_", val)]] <- renderText(paste("Line", val))
})
})
}
shinyApp(ui, server)
app_module_observe.R:
library(shiny)
myModuleUI <- function(id) {
ns <- NS(id)
uiOutput(ns("test"))
}
myModule <- function(input, output, session) {
output$test <- renderUI({
lapply(1:3, function(val) {
fluidRow(column(12,textOutput(session$ns(paste0("line_", val)))))
})
})
observe({
lapply(1:3, function(val) {
output[[paste0("line_", val)]] <- renderText(paste("Line", val))
})
})
}
ui <- fixedPage(
h2("Module example"),
myModuleUI("test_module")
)
server <- function(input, output, session) {
callModule(myModule, "test_module")
}
shinyApp(ui, server)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With