user3245256
user3245256

Reputation: 1948

r Shiny make textInput conditional on a previous selectInput

Hello and sorry for what might be a basic Shiny question.

In my mini-Shiny app, I want the user to:

  1. Pick a name from a list of pre-existing names using selectInput().

  2. Only if the name s/he has in mind is not on the list, I'd like a new widget to appear where s/he should enter the name using textInput().

I am stuck - my verbatimTextOutput statements inside the mainPanel on the UI side are not working.

Thank you for your hints!

library(shiny)

ui = shinyUI(fluidPage(

  sidebarLayout(
    sidebarPanel(
      uiOutput("chosen_name", label = h4("Select one of the names:"))
    ),
    mainPanel(                       # Just shows what was selected
      # Next two lines don't work if uncommented:
      #  verbatimTextOutput('chosen_name')
      #  verbatimTextOutput("name_openend")
    )
  )
))

server = shinyServer(function(input, output, session) {

  # A vector of pre-existing names:
  mynames <- c("John", "Mary", "Jim")

  # Allow to select a name from the list of pre-existing names:
  output$chosen_name <- renderUI({
    selectInput('chosen_name',"Select a name:",
                choices = c("Name not on our list", mynames),
                selected = "Name not on our list")
  })

  # Open end box to enter name - if the name the user wants to enter is not on the list:
  output$name_openend <- renderUI({
    if (!output$chosen_name == 'Name not on our list') return(NULL) else {
      textInput("If the name you want is not on our list, type it here:")
    }
  })

})


shinyApp(ui = ui, server = server)

Upvotes: 1

Views: 2520

Answers (3)

Diego
Diego

Reputation: 422

Updated Code

library(shiny)

ui = shinyUI(fluidPage(

  sidebarLayout(
    sidebarPanel(
      selectInput("chosen_name", "select name", choices = ""),
      uiOutput("new")
    ),
    mainPanel(
      textOutput("chosen")
    )
  )
))

server = shinyServer(function(input, output, session) {

  # A vector of pre-existing names:
  mynames <- c("John", "Mary", "Jim")

  observe({
    updateSelectInput(session, inputId = "chosen_name", label = "Select a name:", choices = c(mynames, "Name not on our list"))
  })

  # Open end box to enter name - if the name the user wants to enter is not on the list:
  output$new <- renderUI({
    if (!input$chosen_name == 'Name not on our list') return(NULL) else {
      textInput("Not_on_list", "If the name you want is not on our list, type it here:")
    }
  })
  #
  # 
  # Allow to select a name from the list of pre-existing names:

  output$chosen <- renderText({
    if (!input$chosen_name == 'Name not on our list') {
    return(paste("Chosen name:", input$chosen_name))
    }
    else {
      return(paste("Chosen name:", input$Not_on_list))
    }
  })

})

shinyApp(ui = ui, server = server)

Upvotes: 1

Tonio Liebrand
Tonio Liebrand

Reputation: 17689

You confused a bit the functions on the ui side: If you use renderUI() on the server side, you will have to use uiOutput() on the ui side to make it work. Also you should avoid using the same id twice. Finally, for the textinput i added an id and a label.

Full code reads:

library(shiny)

ui = shinyUI(fluidPage(

  sidebarLayout(
    sidebarPanel(
      uiOutput("chosen_nm", label = h4("Select one of the names:"))
    ),
    mainPanel(                       # Just shows what was selected
      # Next two lines don't work if uncommented:
      uiOutput("name_openend")
    )
  )
))

server = shinyServer(function(input, output, session) {

  # A vector of pre-existing names:
  mynames <- c("John", "Mary", "Jim")

  # Allow to select a name from the list of pre-existing names:
  output$chosen_nm <- renderUI({
    selectInput('chosen_name',"Select a name:",
                choices = c("Name not on our list", mynames),
                selected = "Name not on our list")
  })

  output$chosen_name2 <- renderText({
    paste("The chosen name is: ", input$chosen_name)
  })

  # Open end box to enter name - if the name the user wants to enter is not on the list:
  output$name_openend <- renderUI({
    req(input$chosen_name)
    if (input$chosen_name == 'Name not on our list'){
      textInput("newName", "If the name you want is not on our list, type it here:")
    }else{
      verbatimTextOutput('chosen_name2')
    }
  })

})


shinyApp(ui = ui, server = server)

Upvotes: 1

Kyle Marsh
Kyle Marsh

Reputation: 66

There were a few things that I needed to cut out to make it work. First was the sidebarLayout. This might have been messing with your mainPanel. I am sure you can get this to work just make sure the mainPanel is in the right place and not being added to the sidebarLayout, which might have been the problem.

There were a few other problems like renderUI and UIOutput. Maybe someone else will add a post on how to use those functions. Also, I added a reactive function so the textOutput would change.

Take a look at how mine works.


mynames <- c("John", "Mary", "Jim")
ui = shinyUI(
  fluidPage(

    sidebarPanel(
      selectInput('chosen_name',"Select a name:",
                  choices = c("Name not on our list", mynames),
                  selected = "Name not on our list")
    ),
    mainPanel(   
      textOutput('chosen_name2')

    )
  )
)

server = shinyServer(function(input, output, session) {

  # A vector of pre-existing names:
  selectedchosen_name <- reactive({
    if (input$chosen_name == 'Name not on our list') {return("Pick a name")} else {
      return("If the name you want is not on our list, type it here:")
    }
  })

  # Allow to select a name from the list of pre-existing names:
  output$chosen_name2 <- renderText({
    selectedchosen_name()
  })

  # Open end box to enter name - if the name the user wants to enter is not on the list:


})

shinyApp(ui = ui, server = server)

I removed some parts that might be redundant, but right now it's simplified so you can add to it. If you have any questions just ask.

Upvotes: 0

Related Questions