Abdelouahed BEN MHAMED
Abdelouahed BEN MHAMED

Reputation: 157

can't communicate data between shiny modules

I am trying to build a shiny App that uses several modules which communicate between them and share data. I have tried to create a simpler example that could be replicated to show the problem I'm facing. The first module allows the user to select a dataset and a column from the selected dataset and then display the column in a table. The server part of the first module returns a list of statistics about the selected column (min,mean, max and sd). The idea is to use these statistics to display them in a second module which creates textOutputs. The problem is that there is no reactivity in the app. Even when changing the dataset and columns the values in the textOutputs is the same.

### Module 1
mod_selectVar_ui <- function(id){
  ns <- NS(id)
  tagList(
    selectInput(ns("dataset"), "Choose a dataset:",choices = c("rock", "pressure", "cars")),
    selectInput(ns("colonnes"),label = "Choose some columns", choices = NULL, multiple = FALSE),
    tableOutput(ns("table"))
  )
}

#'
#' 
mod_selectVar_server <- function(id){
  moduleServer(id, function(input, output, session){
    datasetInput <- reactive({
      switch(input$dataset,
             "rock" = rock,
             "pressure" = pressure,
             "cars" = cars)
    })
    
    observe({
      colonnes <- names(datasetInput())
      updateSelectInput( session, "colonnes", choices = colonnes)
    })
    
    data <- reactive({
      req(input$colonnes)
      datasetInput()[, input$colonnes]
    })
    output$table <- renderTable({
      head(data())
    })
    
    values <- reactive({
      list(
        meanVar = mean(data()),
        maxVar = max(data()),
        minVar = min(data()),
        sdVar = sd(data())
      )
    })
    return(values)
  })
}


### Module 2
mod_textOu_ui <- function(id){
  ns <- shiny::NS(id)
  shiny::tagList(
    shiny::textOutput(ns("txt"))
  )
}

mod_textOu_server <- function(id, texte){
  moduleServer(id,
               function(input, output, session){
                 output$txt <- renderText({
                   texte
                 })
               }
  )
}

### Main App
ui <- fluidPage(
  fluidRow(
    column(3,
           mod_textOu_ui("1")
    ),
    column(3,
           mod_textOu_ui("2")
    ),
    column(3,
           mod_textOu_ui("3")
    ),
    column(3,
           mod_textOu_ui("4")
    )
  ),
  fluidRow(
    mod_selectVar_ui("1")
  )
)

server <- function(input, output, session){
  values <- mod_selectVar_server("1")
  
  mod_textOu_server("1",values()$meanVar)
  
  mod_textOu_server("2",values()$maxVar)
  
  mod_textOu_server("3",values()$minVar)
  
  mod_textOu_server("4",values()$sdVar) 
}

shinyApp(ui ,server )

Upvotes: 0

Views: 438

Answers (1)

lz100
lz100

Reputation: 7360

  1. You have a duplicated ID 1 for you modules mod_selectVar_server("1") and mod_textOu_server("1",values()$meanVar). All IDs must be unique and using a number is not recommended.
  2. Like @Limey said, you can't directly access the reactive value directly on the top level of your server. Reactive values must be accessed inside a reactive context. Pass the reactive directly to the function and access its value later inside your module.
  3. When you change dataset, data will be invalid and it needs to wait for column names to update, so I added req(all(input$colonnes %in% names(datasetInput()))) to prevent the ugly red warnings that will briefly show up.
### Module 1
mod_selectVar_ui <- function(id){
    ns <- NS(id)
    tagList(
        selectInput(ns("dataset"), "Choose a dataset:",choices = c("rock", "pressure", "cars")),
        selectInput(ns("colonnes"),label = "Choose some columns", choices = NULL, multiple = FALSE),
        tableOutput(ns("table"))
    )
}

#'
#' 
mod_selectVar_server <- function(id){
    moduleServer(id, function(input, output, session){
        datasetInput <- reactive({
            switch(input$dataset,
                   "rock" = rock,
                   "pressure" = pressure,
                   "cars" = cars)
        })
        
        observe({
            colonnes <- names(datasetInput())
            updateSelectInput(session, "colonnes", choices = colonnes)
        })
        
        data <- reactive({
            req(input$colonnes)
            req(all(input$colonnes %in% names(datasetInput())))
            datasetInput()[, input$colonnes]
        })
        output$table <- renderTable({
            head(data())
        })
        
        values <- reactive({
            list(
                meanVar = mean(data()),
                maxVar = max(data()),
                minVar = min(data()),
                sdVar = sd(data())
            )
        })
        return(values)
    })
}


### Module 2
mod_textOu_ui <- function(id){
    ns <- shiny::NS(id)
    shiny::tagList(
        shiny::textOutput(ns("txt"))
    )
}

mod_textOu_server <- function(id, texte, item){
    moduleServer(id,
                 function(input, output, session){
                     output$txt <- renderText({
                         texte()[[item]]
                     })
                 }
    )
}

### Main App
ui <- fluidPage(
    fluidRow(
        column(3,
               mod_textOu_ui("m1")
        ),
        column(3,
               mod_textOu_ui("m2")
        ),
        column(3,
               mod_textOu_ui("m3")
        ),
        column(3,
               mod_textOu_ui("m4")
        )
    ),
    fluidRow(
        mod_selectVar_ui("s1")
    )
)

server <- function(input, output, session){
    values <- mod_selectVar_server("s1")
    
    mod_textOu_server("m1",values, "meanVar")
    
    mod_textOu_server("m2",values, "maxVar")
    
    mod_textOu_server("m3",values, "minVar")
    
    mod_textOu_server("m4",values, "sdVar") 
}

shinyApp(ui ,server )

Upvotes: 1

Related Questions