diff --git a/R/input-text.R b/R/input-text.R index ec1b96877..c66894a35 100644 --- a/R/input-text.R +++ b/R/input-text.R @@ -10,6 +10,11 @@ #' @param placeholder A character string giving the user a hint as to what can #' be entered into the control. Internet Explorer 8 and 9 do not support this #' option. +#' @param updateOn A character vector specifying when the input should be +#' updated. Options are `"input"` (default) and `"blur"`. If `"blur"`, then +#' the input value will be updated when the text input loses focus, or when +#' Enter is pressed. +#' @param debounce The debouncing delay in milliseconds when 'input' is used. #' @return A text input control that can be added to a UI definition. #' #' @family input elements @@ -35,7 +40,9 @@ #' #' @export textInput <- function(inputId, label, value = "", width = NULL, - placeholder = NULL) { + placeholder = NULL, updateOn = c("input", "blur"), debounce = 250) { + + updateOn <- match.arg(updateOn) value <- restoreInput(id = inputId, default = value) @@ -43,6 +50,6 @@ textInput <- function(inputId, label, value = "", width = NULL, style = css(width = validateCssUnit(width)), shinyInputLabel(inputId, label), tags$input(id = inputId, type="text", class="shiny-input-text form-control", value=value, - placeholder = placeholder) + placeholder = placeholder, `data-update-on` = updateOn, `data-debounce` = debounce) ) } diff --git a/srcts/src/bindings/input/text.ts b/srcts/src/bindings/input/text.ts index 4da9f6cee..add8bb313 100644 --- a/srcts/src/bindings/input/text.ts +++ b/srcts/src/bindings/input/text.ts @@ -50,20 +50,32 @@ class TextInputBindingBase extends InputBinding { } subscribe(el: TextHTMLElement, callback: (x: boolean) => void): void { - $(el).on( - "keyup.textInputBinding input.textInputBinding", - // event: Event - function () { - callback(true); - } - ); - $(el).on( + const $el = $(el); + const updateOn = $el.data("update-on") || "input"; + + if (updateOn === "input") { + $el.on( + "keyup.textInputBinding input.textInputBinding", + // event: Event + function () { + callback(true); + } + ); + } + + $el.on( "change.textInputBinding", // event: Event function () { callback(false); } ); + + if (updateOn === "blur") { + $el.on("blur.textInputBinding", function () { + callback(false); + }); + } } unsubscribe(el: TextHTMLElement): void { $(el).off(".textInputBinding"); @@ -80,12 +92,15 @@ class TextInputBindingBase extends InputBinding { el; } - getRatePolicy(el: HTMLElement): { policy: "debounce"; delay: 250 } { + getRatePolicy(el: HTMLElement): { policy: "debounce"; delay: number } { + let delay = $(el).data("debounce"); + if (delay === undefined) { + delay = 250; + } return { policy: "debounce", - delay: 250, + delay: delay, }; - el; } } diff --git a/srcts/types/src/bindings/input/text.d.ts b/srcts/types/src/bindings/input/text.d.ts index f521e5ed7..c4db0c2c7 100644 --- a/srcts/types/src/bindings/input/text.d.ts +++ b/srcts/types/src/bindings/input/text.d.ts @@ -16,7 +16,7 @@ declare class TextInputBindingBase extends InputBinding { getState(el: TextHTMLElement): unknown; getRatePolicy(el: HTMLElement): { policy: "debounce"; - delay: 250; + delay: number; }; } declare class TextInputBinding extends TextInputBindingBase {