简体   繁体   中英

RenderUI with conditional selectInput that dynamically builds more selectInputs in Shiny

I am trying to build a Shiny interface with:

  1. a main selector, which decides:
  2. which submenu (input) to show, which decides:
  3. how many subsequent inputs to show

Here's a minimal reproducible example.

If "First" is chosen from the main selector, then a submenu with two possibilities [1,2] exist. These possibilities result in 1 or 2 subsequent inputs being built. So these possibilities:

最初的可能性

If "Second" is chosen from the main selector, then a submenu with two possibilities [3,4] exist. These possibilities result in 3 or 4 subsequent inputs being built.

第二种可能性

ui <- fluidPage(
  radioButtons(inputId="main_selector",label=h5('Select menu'),
               choices = list('First','Second'),selected='First'),
  uiOutput("ui_selected")
)

server <- function(input, output, session) {

  build_inputs <- function(choices){
    output = tagList()
    for(i in 1:choices){
      output[[i]] = tagList()
      output[[i]][[1]] = numericInput(inputId =  paste0(i),
                                      label =  paste0(i),
                                      value = i)
    }
  }

# Are these reactive elements necessary? Should they be in the renderUI below?
  first_submenu <- reactive({
    input$first_submenu
  })
  second_submenu <- reactive({
    input$second_submenu
  })

  output$ui_selected <- renderUI({

    if (input$main_selector == 'First'){
    selectInput(inputId = "first_submenu", label="First submenu",
                choices=list(1,2))

      choices_1 <- first_submenu()
      # Build a list of inputs dependent on the choice above
      output <- build_inputs(choices_1)

    } else if (input$main_selector == 'Second'){
      selectInput(inputId = "second_submenu", label="Second submenu",
                  choices=list(3,4))

      choices_2 <- second_submenu()
      # Build a list of inputs dependent on the choice above
      output <- build_inputs(choices_2)

    # Return output as output$ui_selected element 
    output
  })
}

shinyApp(ui, server)

The error I receive is Warning: Error in :: argument of length 0 . I believe this is because you can't call the outcome of first_submenu from the renderUI element - but I don't know how to structure my code correctly.

I am not sure whether this is what you are after. The main problem was that your function build_inputs does not return anything. The second problem is that choices from selectInput are not numeric, so you need to convert them beforehand. And one other minor problem, related to the error you mention, is that the elements you want to render exist at the same time, so putting a condition on input$first_submenu will trigger errors (even if it is NULL for a couple of milliseconds), so it's (almost always) good practice to take care of possibly null inputs. The last thing I did was to add another uiOutput for the last layer of dynamic inputs. Hope this helps.

ui <- fluidPage(
  radioButtons(inputId="main_selector",label=h5('Select menu'),
               choices = list('First','Second'),selected='First'),
  uiOutput("ui_selected"),
  uiOutput("ui_numeric_inputs")
)

server <- function(input, output, session) {

  build_inputs <- function(choices) {
    output = tagList()
    for(i in 1:choices){
      output[[i]] = tagList()
      output[[i]][[1]] = numericInput(inputId =  paste0(i),
                                      label =  paste0(i),
                                      value = i)
    }
    return(output)
  }

  output$ui_selected <- renderUI({

    if (input$main_selector == 'First'){
      selectInput(inputId = "first_submenu", label="First submenu",
                  choices=c(1,2))
    } else if (input$main_selector == 'Second'){
      selectInput(inputId = "second_submenu", label="Second submenu",
                  choices=list(3,4))
    }
  })

  output$ui_numeric_inputs <- renderUI({
    if (input$main_selector == 'First' && 
(!is.null(input$first_submenu))) {
      build_inputs(as.numeric(input$first_submenu))
    } else if (input$main_selector == 'Second' && 
(!is.null(input$second_submenu))){
      build_inputs(as.numeric(input$second_submenu))
    }
  })
}

shinyApp(ui, server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM