Kaveh akbari
Kaveh akbari

Reputation: 17

Dynamic number of input widgets in shiny

I want to write an app that reads in the uploaded data, then puts enough numericInput due to the number of unique elements in a column (the name of the columns is Big). This question here helped me.

The code is as below:

library(shiny)
 ui <- fluidPage(
  fileInput(inputId = "up","", accept = '.csv'),
  uiOutput("sliders")
)

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

  INPUT <- reactive({
    infile <- input$up

    #validate(need(input$up, "Input a valid filepath."))      

    read.csv(infile$datapath, header = TRUE, sep = ",")
  })

 inVars <- reactive({
    unique(INPUT()$Big)
  })

  output$sliders <- renderUI({
    pvars <- length(inVars())
    lapply(seq(pvars), function(i) {
      numericInput(inputId = paste0("range", pvars[i]),label = pvars[i],value = 1)
    })
  })

}

shinyApp(ui = ui, server = server)

Three questions:

1. When I put

if (is.null(infile))
return(NULL)

instead of validate, it gives me an error which looks like this:

missing value where TRUE/FALSE needed

What should I do to get rid of this error?

2. How could I add a label for each one of the numericInput?

3. How could I use the input values later? In a reactive environment?

Thanks

Upvotes: 0

Views: 1913

Answers (1)

Geovany
Geovany

Reputation: 5697

The problem is not with the if (is.null(infile)) statement, it is with the lapply function. When the Shiny app just starts, the entire server function is executed, the length of inVars() is 0 and the sequence seq(pvars) will be 1 0. Then the numericInput will fail because you are making a reference to pvars[i] when i is equal to 0.

Below is the code that fixes the problem and also answers your questions.

library(shiny)
 ui <- fluidPage(
  fileInput(inputId = "up","", accept = '.csv'),
  uiOutput("sliders")
)

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

  INPUT <- reactive({
    infile <- input$up
    if (is.null(infile))
      return(NULL)
    read.csv(infile$datapath, header = TRUE, sep = ",")
  })

 inVars <- reactive({
    unique(INPUT()$Big)
  })

  output$sliders <- renderUI({
    pvars <- length(inVars())
    if (pvars > 0) {
      div(
        lapply(seq(pvars), function(i) {
          numericInput(inputId = paste0("range", inVars()[i]),label = inVars()[i],value = 1)
        }),
        actionButton("getValues", "Get values"),
        tableOutput('table')
      )
    }
  })

  values <- 0

  # get the values of each numericInput and store them in "values"
  observeEvent(input$getValues, {
      # initialize vector 
      values <<- rep(NA, length(inVars()))
      names(values) <<- inVars()

      for(k in 1:length(inVars())) { 
        inputName <- paste0("range", inVars()[k])
        # only get a value if the numeric input exists
        if (!is.null(inputName))
          values[[k]] <<- input[[inputName]]
      }
    # show values as a table
    output$table <- renderTable(data.frame(
                        variable = inVars(),
                        values))

  })

}

shinyApp(ui = ui, server = server)

Update:

To test the code, use a .csv file with content like:

num,Big
1,a
2,a
3,b
4,b
5,c
6,c
7,d
8,d

Screenshot:

Screenshot

Upvotes: 1

Related Questions