1

I am working with a rather larger Shiny app with several modules. Each tab in the app is its own module. Some of the tabs have some shared inputs, along with distinct inputs to their own tabs.

This is what I need: when a user changes an input in one of the shiny modules, the inputs that are the same across modules need to change as well. This is so that the user doesn't need to keep changing the inputs across tabs when they already changed the input in one tab. Also, ideally the code would not execute until the user navigates to the tab.

Some resources that have given me ideas are the following:

Below I have written some example code of what I am trying to do. Any help is much appreciated. I am hoping a shiny master finds this post. So far, I have been unsuccessful.

library(shiny)

common_inputs_UI <- function(id) {
  ns <- NS(id)
  tagList(
    selectInput(
      ns('common1'),
      'Common 1',
      c('A', 'B', 'C', 'D')
    ),
    selectInput(
      ns('common2'),
      'Common 2',
      c('A2', 'B2', 'C2', 'D2')
    )
  )
}

common_inputs <- function(input, output, session) {
  
  return(
    list(
      common1 = reactive({ input$common1 }),
      common2 = reactive({ input$common2 })
    )
  )
}

test_one_UI <- function(id) {
  ns <- NS(id)
  tagList(
    common_inputs_UI('test1'),
    selectInput(
      'test1_select',
      'Test 1 Select',
      c('Fee 1', 'Fi 1', 'Fo 1', 'Fum 1')
    )
  )
}

test_one <- function(input, output, session, default_inputs) {
  
  ns <- session$ns
  
  observe({
    
    updateSelectInput(
      session,
      'common1',
      selected = default_inputs$common1()
    )
    
    updateSelectInput(
      session,
      'common2',
      selected = default_inputs$common2()
    )
    
  })
}

test_two_UI <- function(id) {
  ns <- NS(id)
  tagList(
    common_inputs_UI('test2'),
    selectInput(
      'test2_select',
      'Test 2 Select',
      c('Fee 2', 'Fi 2', 'Fo 2', 'Fum 2')
    )
  )
}

test_two <- function(input, output, session, default_inputs) {
  
  ns <- session$ns
  
  observe({
    
    updateSelectInput(
      session,
      'common1',
      selected = default_inputs$common1()
    )
    
    updateSelectInput(
      session,
      'common2',
      selected = default_inputs$common2()
    )
    
  })
}

test_three_UI <- function(id) {
  ns <- NS(id)
  tagList(
    common_inputs_UI('test3'),
    selectInput(
      'test3_select',
      'Test 3 Select',
      c('Fee 3', 'Fi 3', 'Fo 3', 'Fum 3')
    )
  )
}

test_three <- function(input, output, session, default_inputs) {
  
  ns <- session$ns
  
  observe({
    
    updateSelectInput(
      session,
      'common1',
      selected = default_inputs$common1()
    )
    
    updateSelectInput(
      session,
      'common2',
      selected = default_inputs$common2()
    )
  
  })
}


ui <- fluidPage(
  tabsetPanel(
    type = 'tabs',
    tabPanel(
      'Test One',
      test_one_UI('test1')
    ),
    tabPanel(
      'Test Two',
      test_two_UI('test2')
    ),
    tabPanel(
      'Test Three',
      test_three_UI('test3')
    )
  )
)

server <- function(input, output, session) {
  
  common_inputs_mod1 <- callModule(common_inputs, 'test1')
  common_inputs_mod2 <- callModule(common_inputs, 'test2')
  common_inputs_mod3 <- callModule(common_inputs, 'test3')
  
  t1 <- callModule(test_one, 'test1', common_inputs_mod1)
  t2 <- callModule(test_two, 'test2', common_inputs_mod2)
  t3 <- callModule(test_three, 'test3', common_inputs_mod3)
  
}

shinyApp(ui, server)
Avery Robbins
  • 132
  • 1
  • 9
  • 1
    Add the common inputs as parameters to the tab modules that ned to react to them and observe changes in the tab modules. Alternatively, create a module for the common inputs and include an instance of that as a sub-module of each tab module. Handle the updating of the common inputs in the common input module. – Limey Jul 09 '21 at 09:25
  • I appreciate your response. Reading your comment, I think I am attempting to at least do some of what you said, but there are gaps in my understanding. Do you know if there is an example of what you suggested posted somewhere? Or if it is simple for you to do would you possibly be able to write up an example as an answer to this post? You'd be helping a stranger out immensely. – Avery Robbins Jul 09 '21 at 13:47
  • 1
    @YBS has given you a workable solution. One small additional observation. `module_server()` is now the recommended way of creating module server functions, and this removes the need for `callModule()`. See [here](https://shiny.rstudio.com/articles/modules.html). – Limey Jul 11 '21 at 07:31
  • I will look into `module_server()`, thanks Limey. – Avery Robbins Jul 12 '21 at 13:46

1 Answers1

1

To display the same common input in all tabs, you need to use the same common_inputs in your calls to different modules (also suggested by @Limey in comments). To use one common input from tab1 and be free to choose other inputs in other tabs, you can use common_inputs_mod1 in all three calls. From your MRE, you can use three observeEvents to provide common inputs from any tab. Try this

server <- function(input, output, session) {
  
  common_inputs_mod1 <- callModule(common_inputs, 'test1')
  common_inputs_mod2 <- callModule(common_inputs, 'test2')
  common_inputs_mod3 <- callModule(common_inputs, 'test3')
  
  observeEvent(common_inputs_mod1, {
    t1 <- callModule(test_one, 'test1', common_inputs_mod1)
    t2 <- callModule(test_two, 'test2', common_inputs_mod1)
    t3 <- callModule(test_three, 'test3', common_inputs_mod1)
  })
  
  observeEvent(common_inputs_mod2, {
    t1 <- callModule(test_one, 'test1', common_inputs_mod2)
    t2 <- callModule(test_two, 'test2', common_inputs_mod2)
    t3 <- callModule(test_three, 'test3', common_inputs_mod2)
  })
  
  observeEvent(common_inputs_mod3, {
    t1 <- callModule(test_one, 'test1', common_inputs_mod3)
    t2 <- callModule(test_two, 'test2', common_inputs_mod3)
    t3 <- callModule(test_three, 'test3', common_inputs_mod3)
  })
}
YBS
  • 19,324
  • 2
  • 9
  • 27
  • This solution works just as I need it! Thank you very much. I was struggling to arrive here so I really appreciate your help. – Avery Robbins Jul 12 '21 at 13:45
  • 1
    You are welcome. If you have more than a few tests, you might want to consider alternative solution suggested by Limey. – YBS Jul 12 '21 at 13:52