In my application, I have one module nested in another. Both the parent and child modules create a UI output using renderUI (a slider) and, based off of the value of this slider, filters data that is displayed on a ggplot. I'm familiar with this pattern in a regular ui/server situation - however, I'm not sure how to access the value of the slider when it's in a module.
The code below shows my attempt to do this for both a module that is called by UI, and by a nested module.
library(shiny)
library(dplyr)
library(ggplot2)
ui <- fluidPage(
fluidRow(
outerModUI("outer")
)
)
outerModUI <- function(id) {
ns <- NS(id)
fluidPage(fluidRow(
uiOutput(ns("outer_slider")),
plotOutput(ns("outer_plot")),
innerModUI(ns("inner"))
))
}
innerModUI <- function(id) {
ns <- NS(id)
fluidPage(fluidRow(
uiOutput(ns("inner_slider")),
plotOutput(ns("inner_plot"))
))
}
server <- function(input, output, session) {
callModule(outerMod, "outer")
output$outer_slider <- renderUI({
sliderInput("slider1", label = "outer slider", min = round(min(mtcars$mpg)),
max = round(max(mtcars$mpg)), value = c(min(mtcars$mpg), max(mtcars$mpg), step = 1))
})
output$outer_plot <- renderPlot({
data <- filter(mtcars, between(mpg, input$slider1[1], input$slider1[2]))
ggplot(data, aes(mpg, wt)) + geom_point()
})
}
outerMod <- function(input, output, session) {
callModule(innerMod, "inner")
}
innerMod <- function(input, output, session) {
output$inner_slider <- renderUI({
sliderInput("slider2", label = "inner slider", min = round(min(mtcars$mpg)),
max = round(max(mtcars$mpg)), value = c(min(mtcars$mpg), max(mtcars$mpg), step = 1))
})
output$inner_plot <- renderPlot({
data <- filter(mtcars, between(mpg, input$slider2[1], input$slider2[2]))
ggplot(data, aes(mpg, wt)) + geom_point()
})
}
shinyApp(ui = ui, server = server)
Joe Cheng provided the answer on the shiny discuss mailing list.
1) In output$inner_slider's renderUI, change sliderInput("slider2", ...) to sliderInput(session$ns("slider2"), ...). This is how you get ahold of the namespace of the current module instance (innerMod).
2) I'd also add this to the first line of output$inner_plot: req(input$slider2)
This indicates that the render of that plot should not continue unless a value for input$slider2 exists (which it won't as the app starts up).
A working gist is here, with renderUI working correctly in both the parent and child modules. https://gist.github.com/tbadams45/38f1f56e0f2d7ced3507ef11b0a2fdce
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