Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shiny: Using uiOutput inside a module, or a nested module?

Tags:

r

shiny

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)
like image 225
tbadams45 Avatar asked Jul 21 '16 20:07

tbadams45


Video Answer


1 Answers

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

like image 138
tbadams45 Avatar answered Sep 19 '22 12:09

tbadams45