R Shiny: test existence of reactive value which is optional after req()

Viewed 238

I have code like this

myfx <- reactive({
  req(
    isTruthy(input$value),
    isTruthy(data1()) || isTruthy(data2())
  )
  ...
  
  if(exists(data2())) {
    # do some stuff
  }
  ## do this other stuff regardless 
})

The if(exists()) piece is where I am stuck. Exists is not the right function here, nor does validate(need(data2())) work. How can I conditionally execute some code if one of the optional reactives (from a group where at least one is required) exists?

EDIT 1: To make explicit the problem, see the issue illustrated by the debug prints below:

myfx <- reactive({
  req(
    isTruthy(input$value),
    isTruthy(data1()) || isTruthy(data2())
  )
  
  print("I am printed, and data2() has not been uploaded by user")
  print(isTruthy(data2()))
  print("I am never printed")

  if(isTruthy(data2())) {
    # do some stuff
  }
  ## do this other stuff regardless 
})

Edit 2: ok I see the reason. And I also see that I'm not observing the behavior in my first req() call because of short-circuiting (||). But now I'm stuck how to achieve the behavior I want. Bascially I don't calculate data2() until the user uploads something (use a req() here too). So that is where this is hanging. But if I remove the req() from the top of this, then I get errors due to trying to work on input that doesn't exist. See the definition for data2() below. How can I fix this?

data2 <- reactive({
    req(input$data2)

    read.csv(input$data2$datapath) %>%
        as_tibble() %>%
        return()
}) 
2 Answers

You can re-use isTruthy. Since it still returns true for 0 rows, you may want to add a check for non-zero row count:

myfx <- reactive({
  req(
    isTruthy(input$value),
    isTruthy(data1()) || isTruthy(data2())
  )
  ...
  
  if (isTruthy(data2()) && nrow(data2()) > 0) {
    # do some stuff
  }
  ## do this other stuff regardless 
})

Or you can capture the attempt in a try/tryCatch and react accordingly:

myfx <- reactive({
  req(
    isTruthy(input$value),
    isTruthy(data1()) || isTruthy(data2())
  )
  ...

  res2 <- tryCatch({
    # do some stuff with data2()
  }, error = function(e) NULL)
  
  ## do this other stuff regardless 
})

Ok, here is the final working solution.

myfx <- reactive({
  req(
    isTruthy(input$value),
    isTruthy(data1()) || isTruthy(data2())
  )
  
  print("I am printed, and data2() has not been uploaded by user")
  print(isTruthy(data2()))
  print("I am never printed")

  if(isTruthy(data2())) {
    # do some stuff
  }
  ## do this other stuff regardless 
})


data2 <- reactive({
    if(isTruthy(input$data2)) {
        read.csv(input$data2$datapath) %>%
          as_tibble() %>%
          return()
    }
}) 
Related