Best way to validate user input and missing values

2,712 views
Skip to first unread message

Morten Joergensen

unread,
Dec 30, 2015, 9:19:50 AM12/30/15
to Shiny - Web Framework for R
Hi

I use numericInput for users to interact with the app which often needs to be validated as the calculations require certain restrictions such as positive numbers. At the same time I do not want to enforce some initial results on the users from some preselected input so I leave the default value as NULL. In order to both restrict the input and make sure all calculations can handle NULL/NA without crashing I use the code below which gets very cumbersome especially with many numeric inputs and calculations/reactive elements.

Any thoughts of doing this smarter? It seems like a typical use case?

ui.R
shinyUI(fluidPage(
   numericInput('value', 'Value',NULL, min = 0),
   textOutput("result"),
   submitButton("Calculate")
))

server.R
shinyServer(function(input, output, session) {
 react <- reactiveValues()
 observe({
   if(is.na(input$value)){return()}
   if(input$value < 0){
     react$value =0
     updateNumericInput(session, "value", value = react$value)
   } else {
     react$value <- input$value
   }
   }, priority = 1
   )
 
 output$result <- renderText({
   if(is.na(input$value)){return()}
   sqrt(react$value)
   })
 })

Best regards

Morten

Homer White

unread,
Jan 3, 2016, 1:32:59 PM1/3/16
to Shiny - Web Framework for R
I think your use-case is very typical:  I face it myself all the time.  So far my solution is to write a gatekeeper-function tailored to my requirements, such as:

exists_as_number <- function(item) {
    !is.null(item) && !is.na(item)
}

Then use it when working with outputs, e.g.:

output$something <- renderText({
    if (exists_as_number(input$numinput) {
        calculations
        return(result)
    }
    NULL
})

It doesn't save much typing but at least I don't forget to add all the right conditions.

Morten Joergensen

unread,
Jan 3, 2016, 4:56:39 PM1/3/16
to Shiny - Web Framework for R
Thank you very much for your answer. A good idea to use a function to streamline the check for missing input. It still gets messy when having many input-variables though. I think I have gotten a little closer to some other solutions:

For checking for missing inputs I make a reactive function missing() which is true whenever any input is not set:
missing <- reactive({
    any(is.na(reactiveValuesToList(input)))
  })
This can be checked in reactives or outputs as in your example. It would be great if there was some method to stop all reactive events when this is true but I haven't found any such yet.

For validating input and forcing it to be within some limits (e.g. >0) I think I will use java script as my shiny apps already use a custom js file. I am no expert on js but my code looks like this
function LT(number1,number2) {return (number1 < number2);}
function LE(number1,number2) {return (number1 <= number2);}
function GT(number1,number2) {return (number1 > number2);}
function GE(number1,number2) {return (number1 >= number2);}

function toSymbol(expr) {
  if(expr=="LT"){return("<")}
  if(expr=="LE"){return("≤")}
  if(expr=="GT"){return(">")}
  if(expr=="GE"){return("≥")}
}

function validate(inputID, expr, limit){
  var element = document.getElementById(inputID);
  element.onchange=function(){
    if(expr(element.value,limit)){return}
      else {
        label = element.previousElementSibling.innerText;
        swal({
          title: label + " has to be " + toSymbol(expr.name) + " " + limit,
          confirmButtonText: "OK" });
        element.value = null}
  };
}
(The swal function is simply an alert box from the library sweetalert.js. The alert() could be used as well)

I use a java script string and sendCustomMessage to send from server.R and with the above js file I can write in server.R
validate('myInputID',GE,0);

and if the user enters any negative value an alert box will show saying 'myInputLabel' has to be ≥ 0 while the input is set to null. I think this is handy as most of the js is "hidden" in the custom js file and it is easy to have an overview of all the validating rules of the inputs in the server.R which would look like
validate(firstInputID,expr,limit);
validate(secondInputID,expr,limit);
...

A build-in validating function in shiny would be nice though :o)

Morten

Homer White

unread,
Jan 3, 2016, 8:59:05 PM1/3/16
to Shiny - Web Framework for R
Morten,

It looks like what you want is here:

http://shiny.rstudio.com/articles/validation.html

But you probably know about it already, so maybe I am not understanding what you really want.


On Wednesday, December 30, 2015 at 9:19:50 AM UTC-5, Morten Joergensen wrote:

Morten Joergensen

unread,
Jan 4, 2016, 8:46:35 AM1/4/16
to Shiny - Web Framework for R
Wow! That is embarrassing. I cannot figure out how I could miss that function. In my initial googling I actually found several other users with similar issues and I also thought I had read all of the articles on Shiny. My search strings must have been way off.

Thank you for your help and sorry for the inconvenience.

Morten

Homer White

unread,
Jan 4, 2016, 8:58:26 AM1/4/16
to Shiny - Web Framework for R
Believe me, I have embarassed myself even worse with Shiny!

Joe Cheng

unread,
Jan 4, 2016, 12:38:03 PM1/4/16
to Homer White, Shiny - Web Framework for R
validate(need(...)) is definitely intended for this. We've also recently added a streamlined version called "req", where req(x) is equivalent to calling validate(need(x, message = FALSE)). (You would still use validate/need if you want to show a message when x is missing. But it turns out you don't want to show a message in 95% of cases.)


I've rewritten your original example to use a reactive expression instead of reactive value:

shinyServer(function(input, output, session) {

  value <- reactive({
    req(input$value)
    max(input$value, 0)
  })

  observe({
    updateNumericInput(session, "value", value())
  })

  output$result <- renderText({
    sqrt(value())
  })
})

--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/1bf21459-0236-4e31-a0af-5983383213fb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Morten Joergensen

unread,
Jan 4, 2016, 5:34:20 PM1/4/16
to Shiny - Web Framework for R, homerh...@gmail.com
Thats very handy and makes the code much more readable. My check for missing input is now one simple line

req(!any(is.na(reactiveValuesToList(input))))

Thanks.

Morten

Joe Cheng

unread,
Jan 4, 2016, 5:59:07 PM1/4/16
to Morten Joergensen, Shiny - Web Framework for R, homerh...@gmail.com
The only problem with reactiveValuesToList is that whoever's calling that is taking a reactive dependency on EVERY input.

Also I don't know if it was clear, but in my example I only called req() from the reactive, not from the outputs. That's because if the req() call fails in the reactive, it will stop processing not only itself but whoever called it--it's implemented as a special kind of error. In other words:

a <- function(x) {
  req(x)
  print("a")
}

b <- function(x) {
  a(x)
  print("b")
}

b(1) # prints both "a" and "b"
b(NULL) # prints nothing, errors

--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.

Morten Joergensen

unread,
Jan 5, 2016, 2:43:39 AM1/5/16
to Shiny - Web Framework for R, morten.joer...@gmail.com, homerh...@gmail.com
Yes, thanks for the clarification. The code was intended to stop everything if any input was missing but it might be better to specify the input variables. I very much like that the req (and validate) can trace back dependencies and stop them - it makes it very powerfull.

Morten

Morten Joergensen

unread,
Jan 8, 2016, 4:33:57 AM1/8/16
to Shiny - Web Framework for R, morten.joer...@gmail.com, homerh...@gmail.com
Just wanted to share if anyone comes by this thread:

It seems that ggvis (which I use in many of my apps) does not play along nicely with validate/req. It works somehow if ggvis is wrapped in a reactive/observe and the reactive data function (with parentheses) is passed to ggvis i.e.

observe({
  data
() %>%
    ggvis
()%>%
     bind_shiny
()
)}

This may cause some inefficient renderings of the plot though

Morten
Reply all
Reply to author
Forward
0 new messages