2

I am struggling with a workflow to pass a reactive dataset and function to a module in shiny. I have made a simple version of what I mean below; the app simply prints the mean mpg for a each value of cyl.

library(shiny)

# Module 
textToolUI <- function(id){
  ns <- NS(id)
  textOutput(ns("text"))
} 

textTool <- function(input, output, session, value){
  output$text <- renderText({paste(value)})
}



# App
ui <- basicPage(
  selectInput("carbSelect", "Carburetor Selector", choices = c(1,2,3,4)),
  textToolUI("text1")
)

server <- function(input, output, session){
  data <- reactive(filter(mtcars, carb == input$carbSelect))
  myfunc <- function(x){return(mean(x))}

  callModule(textTool, "text1", value = myfunc(data$mpg))  # This throws up the "object of type closure not subsettable" error
                                                           # Using data()$mpg means it is not reactive
}

shinyApp(ui = ui, server = server) 

The problem arises due to the fact that both the dataset and function (myfunc) need to sit outside the module. In my actual app there are multiple different datasets and functions used.

I assume the problem here is that the function is evaluated before the reactive dataset and hence I need a different work flow but I can't think of a suitable alternative.

Ben Cannon
  • 23
  • 2
  • The value needs to be reactive, check out a very similar issue I had at this answer: https://stackoverflow.com/questions/36695577/shiny-module-that-calls-a-reactive-data-set-in-parent-shiny-server - in your case I think `myfunc()` needs to be in the module, and `data` passed in as the value (without parans e.g. not `data()`) - it needs to be a reactive object. – MarkeD Jul 10 '18 at 14:02

1 Answers1

0

The module needs to be passed a reactive object only, no params.

The example below moves the function into the module, and turns it into a table instead of text as mean(mtcars) was outputting NA

library(shiny)

myfunc <- function(x){colMeans(x)}

myfunc2 <- function(x){colSums(x)}

# Module 
textToolUI <- function(id){
  ns <- NS(id)
  tableOutput(ns("text"))
} 

textTool <- function(input, output, session, value, f){

  output$text <- renderTable({
    req(value())
    paste(f(value()))
    })
}



# App
ui <- basicPage(
  selectInput("carbSelect", "Carburetor Selector", choices = c(1,2,3,4)),
  p("myfunc1 - colMeans"),
  textToolUI("text1"),
  p("myfunc2 - colSums"),
  textToolUI("text2")
)

server <- function(input, output, session){
  data <- reactive(dplyr::filter(mtcars, carb == input$carbSelect))

  callModule(textTool, "text1", value = data, f = myfunc)

  callModule(textTool, "text2", value = data, f = myfunc2)
  # Using data()$mpg means it is not reactive
}

shinyApp(ui = ui, server = server) 
MarkeD
  • 2,500
  • 2
  • 21
  • 35