7

In Shiny, if I have a numericInput as an input, when the user manually enters a value, it is not recognizing or respecting the max/min value and allows any number.If the user selects an arrow for the dropdown it respects the values but just not when entered manually. How can I have the manual entry respect the upper/lower value bounds?

numericInput("test", label=("TestLabel"), min=0, max=10, value="", step = 1.0),
Dante Smith
  • 561
  • 1
  • 6
  • 21
  • 1
    It was reported as a bug https://github.com/rstudio/shiny/issues/927, assigned to an improvement request then closed... but it seems it needs to be reopened – HubertL Jan 17 '17 at 21:02
  • By now there is an official way to solve this: https://github.com/rstudio/shiny/issues/927#issuecomment-849664075 using the the {[shinyvalidate](https://rstudio.github.io/shinyvalidate/)} package. – ismirsehregal Jun 22 '21 at 06:45

1 Answers1

7

As @HubertL pointed out it is a reported bug.

So you have two possibilities:

  1. Accept a small work around, see below or
  2. Wait for it to be fixed

In case an ugly work around is useful for you until it is fixed:

library(shiny)

ui <- fluidPage(
  uiOutput("numInput"),
  textOutput("text")
)

server <- function(input, output) {
  global <- reactiveValues(numVal = 25, numMin = 1, numMax = 100)

  numVal <- reactive({
    if(!is.null(input$num)){
      if(input$num < global$numMin) return(global$numMin)
      if(input$num > global$numMax) return(global$numMax)     
      return(input$num)
    }else{
      return(global$numVal)
    }
  })

  output$numInput <- renderUI(numericInput("num", "", min = global$numMin, 
                              max = global$numMax, value = numVal()))

  output$text <- renderText(input$num)
}

shinyApp(ui, server)

Downside is that you cant change values as fast with the up/down "arrows".

Edit: Request to generalize the answer for multiple inputs:

library(shiny)
amtInputs <- 6

ui <- fluidPage(uiOutput("numInput"))

server <- function(input, output) {
  global <- reactiveValues(numVal = rep(25, amtInputs), numMin = rep(1, amtInputs), 
          numMax = rep(100, amtInputs))

  numVal <- reactive({
    out <- rep(0, amtInputs)
    for(idNr in 1:amtInputs){
      id <- paste0("num", idNr)      
      if(!is.null(input[[id]])){
        out[idNr] <- input[[id]]
        if(input[[id]] < global$numMin[idNr]) out[idNr] <- global$numMin[idNr]
        if(input[[id]] > global$numMax[idNr]) out[idNr] <- global$numMax[idNr]
      }else{
        out[idNr] <- global$numVal[idNr]
      }
    }
    return(out)
  })

  output$numInput <- renderUI({
    inputs <- tagList()
    for(idNr in 1:amtInputs){
      inputs <- tagList(inputs, numericInput(paste0("num", idNr), "", 
 min = global$numMin[idNr], max = global$numMax[idNr], value = numVal()[idNr]))
    }
    return(inputs)
  })
}
shinyApp(ui, server)
Tonio Liebrand
  • 17,189
  • 4
  • 39
  • 59
  • How would this functionality work if I had multiple numericInputs? Would I have to duplicate the server reactive functions for each numericInput? Let's say I have 6 numericInputs. – Dante Smith Jan 18 '17 at 15:36
  • 1
    Hi @DanteSmith, see the edit above for a generalization. Duplicating works of course, but I think you thought of sthg shorter, so see the for loop above. You can try apply() for sthg more fancy ;) – Tonio Liebrand Jan 18 '17 at 17:08
  • Thanks Tonio! Could this handle if the initial value of the numericInput is NA as opposed to a default of a number between 0-100? I ask in that the numeric input would only change the value if a value is entered and the value exeeds the min and max listed. – Dante Smith Jan 18 '17 at 19:14
  • Hi @DanteSmith, Your last sentence is of course possible, why you would like to pass an NA i dont really get. How about, ignore the input value as long he is within the confidence value of 0-100? Anyway I think it would be the best to open a new question, because it is not related to the bug anymore. Hope that helps! – Tonio Liebrand Jan 18 '17 at 19:28