Search code examples
rshinyshiny-reactivityshinyvalidate

shinyvalidate - using a reactive expression witin add_rule()


I am trying to implement user feedback for an app I'm working on using the shinyvalidate package. Some of the feedback I want to communicate to the user is whether a value they have selected is within a specific range or not. The range of interest depends on another input they have made (I have included a simplified repex of the code).

Thus, whether the precondition of interest is met depends on a reactive value. I first define a function that checks whether a provided value is within a specified range. Then I call this function within add_rule() using a reactive as an argument to the function. This results in an error, which states that I cannot access the reactive using add_rule. This is supposedly the case because the InputValidator object is not a reactive consumer.

Error message:

Warning: Error in Can't access reactive value 'num1' outside of reactive consumer.
i Do you need to wrap inside reactive() or observer()?
  55: <Anonymous>
Error: Can't access reactive value 'num1' outside of reactive consumer.
i Do you need to wrap inside reactive() or observer()?

However, if I use an unnamed function within add_rule(), I can specify a range that depends on a reactive and I no longer get the error message. The unnamed and named functions I use are identical and I don't understand why I get an error message using a named function but I do not get the error message when using the named function.

Here is my code using the named function:

library(shiny)
library(shinyvalidate)
checkRange <- function(value, value2){
  if(value < -2 * value2 || value > 2 * value2 ){
    paste0("Please specify a number that is within the range: ", -2 * value2, ":", 2 * value2, " - Tank you!")
  }
}

ui <- fluidPage(
  fluidRow(
           numericInput("num1",
                        "Please specify your first number",
                        value = NULL),
           numericInput("num2",
                        "Please specify a different number",
                        value = NULL),
           verbatimTextOutput("selectedNums")
  
)
)

server <- function(input, output, session){
  iv <- InputValidator$new()
  iv$add_rule("num1", sv_required())
  iv$add_rule("num2", sv_required())
  iv$add_rule("num2", checkRange, value2 = input$num1)
  iv$enable()
  output$selectedNums <- renderPrint({
    req(iv$is_valid())
    paste0("The first number = ", input$num1, " and the second number = ", input$num2)
  })
}

app <- shinyApp(ui, server)

runApp(app)

And here is the code using an anonymous function (UI and server code are largely identical except one call to iv$add_rule()):

library(shiny)
library(shinyvalidate)
ui <- fluidPage(
  fluidRow(
           numericInput("num1",
                        "Please specify your first number",
                        value = NULL),
           numericInput("num2",
                        "Please specify a different number",
                        value = NULL),
           verbatimTextOutput("selectedNums")
  
)
)

server <- function(input, output, session){
  iv <- InputValidator$new()
  iv$add_rule("num1", sv_required())
  iv$add_rule("num2", sv_required())
  iv$add_rule("num2", function(value){
    if(value < - 2 * input$num1 || value > 2 * input$num2){
      paste0("Please specify a number that is within the range: ", -2 * input$num1, ":", 2 * input$num1, " - Tank you!")
    }
  })
  iv$enable()
  output$selectedNums <- renderPrint({
    req(iv$is_valid())
    paste0("The first number = ", input$num1, " and the second number = ", input$num2)
  })
}

app <- shinyApp(ui, server)

runApp(app)

I would prefer to use the named function since I would like to reuse the code multiple times. Could anyone help me out as to why I get an error message with the named function but not with the unnamed one?


Solution

  • You could do:

      iv$add_rule("num2", function(value){checkRange(value, input$num1)})