Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions R/validator.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#' Shiny server functions and Shiny module server functions. The Shiny app
#' author can register zero, one, or multiple validation rules for each input
#' field in their UI, using the `InputValidator$add_rule()` method.
#' `InputValidator$remove_rules()` can be used to remove all rules pertaining
#' to a given input field.
#'
#' Once an `InputValidator` object is created and populated with rules, it can
#' be used in a few ways:
Expand Down Expand Up @@ -192,6 +194,29 @@ InputValidator <- R6::R6Class("InputValidator", cloneable = FALSE,
private$rules(c(shiny::isolate(private$rules()), stats::setNames(list(rule_info), inputId)))
invisible(self)
},
#' @description Remove all rules pertaining to a given inputId. (It's safe
#' to call remove_rules() for inputIds for which no rules have been added.)
#'
#' @param inputId A single-element character vector indicating the ID of the
#' input that the rules apply to. (Note that this name should _not_ be
#' qualified by a module namespace; e.g. pass `"x"` and not
#' `session$ns("x")`.)
#' @param session. The session object to which the input belongs. (There's
#' almost never a reason to change this from the default.)
remove_rules = function(inputId, session. = shiny::getDefaultReactiveDomain()) {
all_rules <- shiny::isolate(private$rules())
all_rules[names(all_rules) == inputId] <- NULL
# if the validator is enabled, disable then enable it again to update the
# displayed validation feedback in the user interface
if (private$enabled) {
self$disable()
private$rules(all_rules)
self$enable()
} else {
private$rules(all_rules)
}
invisible(self)
},
#' @description Begin displaying input validation feedback in the user
#' interface. Once enabled, this validator object will automatically keep
#' the feedback up-to-date. (It's safe to call the `enable()` method
Expand Down
30 changes: 30 additions & 0 deletions man/InputValidator.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions shinyvalidate.Rproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Version: 1.0
ProjectId: ea5074a3-d641-4ec6-83e9-9a148f132225

RestoreWorkspace: Default
SaveWorkspace: Default
Expand Down
62 changes: 62 additions & 0 deletions tests/testthat/test-validator.R
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,68 @@ test_that("InputValidator add_rule() stops on first failing rule", {
})
})

test_that("InputValidator remove_rules()", {

session <- shiny::MockShinySession$new()
shiny::withReactiveDomain(session, {
iv <- InputValidator$new()

iv$add_rule("inputA", shiny::need, message = "Input A is required")
iv$add_rule("inputB", function(value) {
if (is.null(value)) {
"Input B is required"
}
})
iv$add_rule("inputC", ~ if (is.null(.)) "Input C is required")

shiny::isolate({
expect_false(iv$is_valid())

expect_identical(iv$validate(), rlang::list2(
!!session$ns("inputA") := list(type = "error", message = "Input A is required", is_html = FALSE),
!!session$ns("inputB") := list(type = "error", message = "Input B is required", is_html = FALSE),
!!session$ns("inputC") := list(type = "error", message = "Input C is required", is_html = FALSE)
))
})

iv$remove_rules("inputC")

shiny::isolate({
expect_false(iv$is_valid())

expect_identical(iv$validate(), rlang::list2(
!!session$ns("inputA") := list(type = "error", message = "Input A is required", is_html = FALSE),
!!session$ns("inputB") := list(type = "error", message = "Input B is required", is_html = FALSE)
))
})

session$setInputs(
"inputB" = TRUE,
)
shiny::isolate({
expect_false(iv$is_valid())
expect_identical(iv$validate(), rlang::list2(
!!session$ns("inputA") := list(type = "error", message = "Input A is required", is_html = FALSE),
!!session$ns("inputB") := NULL
))
})

iv$remove_rules("inputC")
iv$remove_rules("inputB")

session$setInputs(
"inputA" = TRUE,
)

shiny::isolate({
expect_true(iv$is_valid())
expect_identical(iv$validate(), rlang::list2(
!!session$ns("inputA") := NULL
))
})
})
})

test_that("Empty InputValidator works as expected", {
session <- shiny::MockShinySession$new()
shiny::withReactiveDomain(session, {
Expand Down