Search code examples
rshinymoduleshinywidgets

Update Radio buttons using a Reactive Value fed to a Module, R Shiny


I am building a shiny app and will have the same radio button inputs on multiple pages that will change what is shown on the page. I am putting these radio buttons inside a module so I don't have to reproduce that code in multiple places. They will all have a static set of choices, but I want them all to maintain the same selected value throughout the app. This will mean any time you change a page, the same value is selected as before. If I select A on one page, all other pages will have A selected as well until I choose a different option on any other page.

I haven't been having any luck with any of my attempts thus far. This explanation seems close to what I am looking for, but I haven't been able to make it work. In the app below I feel like I should be able to pass the modServer function a reactive value that will update the associated radio buttons to the same selected value. If I can make this single module update based on input$tmp I think I should be able to replicate that across multiple iterations of the module.

EDIT: Updated code. App now has checks to look at the value of input$tmp outside of the module as itself and a reactive value. Also within the module as the input as well as a new reactive value.

New Question: Why is it showing none of these variables as a reactive variable? It must be why the observeEvent isn't working inside the modServer. The renderText show those values are updating, but it's not triggering the updateRadioGroupButtons.

library(shiny)
library(shinyWidgets)

# UI module
modUI <- function(id){
  ns <- NS(id)
  tagList(
      shinyWidgets::radioGroupButtons(
        inputId = ns("radio"),
        choices = c('A', 'B', 'C', 'D'),
        selected = 'A'),
      uiOutput(ns('modtest')),
      uiOutput(ns('modtest2'))
  )

}
# Server module
modServer <- function(id, .selected){
  moduleServer( id, function(input, output, session){
    ns <- session$ns
  
    mod_rval <- reactive({ .selected() })    
        
    output$modtest <- renderText({
      paste('mod_rval() is:', mod_rval(), 'and is reactive: ', is.reactive(mod_rval()))
    })
    
    output$modtest2 <- renderText({
      paste('.selected() is:', .selected(), 'and is reactive: ', is.reactive(.selected()))
    })
    
    observeEvent(.selected(), {
      shinyWidgets::updateRadioGroupButtons(
        session,
        inputId = ns("radio"),
        choices = c('A', 'B', 'C', 'D'),
        selected = .selected()
      )
    })
  
  })
}

# APP
ui <- fluidPage(
  selectInput('tmp', 'tmp : input value', choices = c('A','B','C','D')),
  modUI(id='mod1'),
  uiOutput('test'),
  uiOutput('test2')
)

server <- function(input, output, session) {
  
  # functioning.
  rval <- reactive({input$tmp})
  modServer(id = 'mod1', .selected = rval)

  output$test <- renderText({
    paste('rval() is: ', rval(), 'and is reactive: ', is.reactive(rval()))
  })
  
  output$test2 <- renderText({
    paste('input$tmp is: ', input$tmp, 'and is reactive: ', is.reactive(input$tmp))
  })
  
}

shinyApp(ui, server)

Solution

  • You don't need ns in updateRadioGroupButtons(...), and you really need to update in a different server module as one is affecting the other. Try this

    library(shiny)
    library(shinyWidgets)
    
    # UI module
    modUI <- function(id){
      ns <- NS(id)
      shinyWidgets::radioGroupButtons(
        inputId = ns("radio"),
        choices = c('A', 'B', 'OK', 'Whatever'),
        selected = 'A')
      
    }
    # Server module 1
    modServe <- function(id){
      moduleServer( id, function(input, output, session){
        return(reactive(input$radio))
      })
    }
    # Server module 2
    modServer <- function(id, selected){
      moduleServer( id, function(input, output, session){
        
        observe({
          print(selected())
          shinyWidgets::updateRadioGroupButtons(
            session,
            inputId = "radio",
            choices = c('A', 'B', 'C', 'D'),
            selected = selected()
          )
        })
        
      })
    }
    
    # APP
    ui <- fluidPage(
      modUI(id='mod1'),
      modUI(id='mod2')
    )
    
    server <- function(input, output, session) {
      m1 <- modServe("mod1")
      m2 <- modServe("mod2")
      
      modServer("mod2",m1)
      modServer("mod1",m2)
    }
    
    shinyApp(ui, server)