I was thinking that there would be a solution at the level of R/shiny. But I have found a solution that uses javascript.
library(shiny)
js <- '
$(document).on("keyup", function(e) {
minChars = 4;
tag1 = document.activeElement.getAttribute("id");
val1 = document.activeElement.value;
if (tag1 == "input1-selectized") {
if (Math.sign(val1.length +1 - minChars) == 1) {
obj = { "val": val1 };
Shiny.onInputChange("valueEntered", obj);
}
}
});
'
ui <- fluidRow(
tags$script(js),
selectizeInput(
"input1",
"Enter text",
choices = c("A", "B"),
options = list(create = FALSE)),
textOutput("output1")
)
server <- function(input, output, session) {
output$output1 <- renderText({
req(input$valueEntered$val)
input$valueEntered$val
})
}
shinyApp(ui = ui, server = server)
The javascript looks for text entered into the element with id "input1-selectized", and if the value is length 4 or more, sets the shiny variable "valueEntered" to an object with val = the text.
Then the observeEvent uses the shiny variable input$valueEntered to set the output text.
The reason in the javascript for using the Math.sign function rather than >, and the reason for nested if's is because for some reason, Shiny replaces infix operators such as > and && by their html equivalents, > and &&.
Note that if the selectizeInput widget has id "input1", then the corresponding text field has id "input1-selectized".