Reputation: 591
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),
Upvotes: 9
Views: 3588
Reputation: 11
After so many years, this problem has not been fixed in Shiny. The workaround seems complicated. There is also a shinyvalidate package being proposed as a solution, but it does not enforce a upper or lower limit.
One alternative solution I found is to use JavaScript code to customize the behavior and enforce a limit. In the example below, a numericInput must be bigger than 1. If the user enters a value that is smaller than 1, a warning message is shown and the value is set to 1.5 after 2 seconds.
library(shiny)
ui <- fluidPage(
tags$head(
tags$script(HTML("
$(document).on('shiny:connected', function(event) {
$('#limma_fc').on('input', function() {
var inputElement = $(this);
setTimeout(function() {
var value = parseFloat(inputElement.val());
if (value < 1) {
inputElement.val('1.5');
alert('Must be greater than 1');
inputElement.trigger('change'); // trigger update
}
}, 2000); // Wait for 2 seconds
});
});
"))
),
numericInput("limma_fc", "Limma FC:", value = 1.5, min = 1, max = 100, step = 0.5),
verbatimTextOutput("value")
)
server <- function(input, output, session) {
output$value <- renderText({
paste("Current value:", input$limma_fc)
})
}
shinyApp(ui, server)
Upvotes: 1
Reputation: 17699
As @HubertL pointed out it is a reported bug.
So you have two possibilities:
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)
Upvotes: 7