its.me.adam
its.me.adam

Reputation: 706

How to show or hide a textInput in R shiny depending on a radioButton choice?

In my reprex below, Number duplicates the inputs. I am stuck on how to achieve two things.

  1. If the Contractor radio button option is selected, show a text input with label "Name of Contractor".

  2. How can I have the radio button input set as empty? I know selected = character(0) achieves this, but it causes another challenge: if an option is selected, and then Number is changed, the radio button selection will disappear. In my reprex, the radio button selection will not be affected after Number is changed, but the default selection is the first choice, whereas I would like the default to be empty.

library(shiny)

ui <- fluidPage(
  numericInput("n", "Number", value = 1),
  uiOutput("col")
)


server <- function(input, output, session) {
  
  # Dynamic UI: Multiple Controls -------------------------------------------
  
  col_names <- reactive(paste0("staff_attended_", seq_len(input$n)))
  
  output$col <- renderUI({
    map(
      col_names(), 
      ~ tagList(
          selectInput(
            .x,
            label = "Staff Attended",
            choices = letters,
            selected = isolate(input[[.x]]),
            multiple = TRUE
          ),
          
          radioButtons(
            paste0(.x, "_type"), 
            "Staff Attended: Shift/Call-In/Contractor?",
            choices = c("Shift", "Call-In", "Contractor"),
            selected = isolate(input[[paste0(.x, "_type")]])
          )
          
      )
    )
  })
}

shinyApp(ui, server)

Upvotes: 0

Views: 187

Answers (1)

Jan
Jan

Reputation: 9133

If the Contractor radio button option is selected, show a text input with label "Name of Contractor".

Therefore we can use a conditionalPanel which contains a textInput. The condition can be written as

paste0(
   "(document.querySelector('input[name=\"",
   .x,
   "_type\"]:checked') || {value: 'dummy'}).value === 'Contractor'"
)

Explanation:

  • The document.querySelector call aims for the checked value of the radioButtons. The relevant checkbox id is assigned by .x inside your map call. It shall return TRUE if this value is "Contractor".
  • Since you would like to have empty radioButtons when starting the app, the querySelector would be null while being in this state. Hence, the || {value: 'dummy'}) will yield a dummy value such that there won't be an error and the textInput is hidden by the start of the app. Otherwise, the || operator will short-circuit.

enter image description here

How can I have the radio button input set as empty? I know selected = character(0) achieves this, but it causes another challenge: if an option is selected, and then Number is changed, the radio button selection will disappear...

In order to retain the selection when the number is changed, we put an observeEvent on input$n and use an updateRadioButtons, which will affect the selected parameter using isolate.

observeEvent(input$n, {
    map(col_names(),
        ~ tagList(
            updateRadioButtons(session, paste0(.x, "_type"),
                               selected = isolate(input[[paste0(.x, "_type")]]))
        ))
})

enter image description here

Complete minimal example:

library(shiny)

ui <- fluidPage(numericInput("n", "Number", value = 1),
                uiOutput("col"))


server <- function(input, output, session) {
    # Dynamic UI: Multiple Controls -------------------------------------------
    
    col_names <-
        reactive(paste0("staff_attended_", seq_len(input$n)))
    
    observeEvent(input$n, {
        map(col_names(),
            ~ tagList(
                updateRadioButtons(session, paste0(.x, "_type"),
                                   selected = isolate(input[[paste0(.x, "_type")]]))
            ))
    })
    
    output$col <- renderUI({
        map(col_names(),
            ~ tagList(
                selectInput(
                    .x,
                    label = "Staff Attended",
                    choices = letters,
                    selected = isolate(input[[.x]]),
                    multiple = TRUE
                ),
                
                radioButtons(
                    paste0(.x, "_type"),
                    "Staff Attended: Shift/Call-In/Contractor?",
                    choices = c("Shift", "Call-In", "Contractor"),
                    selected = character(0)#isolate(input[[paste0(.x, "_type")]])
                ),
                
                conditionalPanel(
                    paste0(
                        "(document.querySelector('input[name=\"",
                        .x,
                        "_type\"]:checked') || {value: 'dummy'}).value === 'Contractor'"
                    ),
                    textInput("NameContractor", "Name of Contractor")
                )
                
            ))
    })
}

shinyApp(ui, server)

Upvotes: 1

Related Questions