sabsus
sabsus

Reputation: 23

Get a boolean on the existence of a reactive value in shiny

Situation

I would like to use multiple reactive values (in example ab and cd) to create a new one (in example merge). It is possible that only some are available (in example ab or cd or both), because not every category available needs to be calculated. The idea is to check for the existence of the according reactive value and, depending on it, add or skip the according category.

Approaches not working

Proposed methods for checking/validating reactive values include req(), validate(), need() and isTruthy(), but these generate an error, not an (to my knowledge) usable return like TRUE or FALSE. exists() seems not to be able to handle an non-existing reactive value, even though I would think it would be the ideal function (giving TRUE or FALSE depending on the existence of a variable). Edit 1: is.null() does not work either. When the according reactive value is not existent yet, the function is exited as with the other approaches. To clarify: It seems each time a non-existent reactive value is called the function is exited. Edit 1

Question

Is there a possibility to check for the existence of a reactive value in shiny, with result, not an error (or an idea for a workaround)?

Please see the code, in this example with exists().

ui <- fluidPage(
  # inputs first reactive value
  sliderInput("a",
              "a",
              1, 10, 2 ,1),
  sliderInput("b",
              "b",
              1, 10, 4 ,1),
  # calculate first reactive value
  actionButton("ab", "calc a + b"),

  # inputs second reactive value
  sliderInput("c",
              "c",
              1, 10, 6 ,1),
  sliderInput("d",
              "d",
              1, 10, 8 ,1),
  # calculate second reactive value
  actionButton("cd", "calc c + d"),

  # outputs
  verbatimTextOutput("result_ab"),
  verbatimTextOutput("result_cd"),
  verbatimTextOutput("result_merge")
)

server <- function(input, output, session) {
  # outputs
  output$result_ab <- renderPrint(ab())
  output$result_cd <- renderPrint(cd())
  output$result_merge <- renderPrint(merge())
  
  # calculations 
  ab <- eventReactive(input$ab,{
    ab <- input$a + input$b
    ab
  })
  
  cd <- eventReactive(input$cd,{
    cd <- input$c + input$d
    cd
  })
  
  # merge of existing values
  merge <- reactive({
    merge <- c() # empty vector to be filled up
    
    if(exists(ab())){
      merge <- c(merge, ab())
    }

    if(exists(cd())){
      merge <- c(merge, cd())
    }

    merge
  })
  
}

shinyApp(ui, server)

Thank you!

Upvotes: 2

Views: 556

Answers (2)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84519

I don't know the correct wording, but roughly speaking, since merge() depends on ab() and cd(), it is "invalidated" (it does not run) as long as ab() or cd() do not "exist". At least this is what I think.

You can use reactive values and observers instead:

library(shiny)

ui <- fluidPage(
  # inputs first reactive value
  sliderInput("a",
              "a",
              1, 10, 2 ,1),
  sliderInput("b",
              "b",
              1, 10, 4 ,1),
  # calculate first reactive value
  actionButton("ab", "calc a + b"),

  # inputs second reactive value
  sliderInput("c",
              "c",
              1, 10, 6 ,1),
  sliderInput("d",
              "d",
              1, 10, 8 ,1),
  # calculate second reactive value
  actionButton("cd", "calc c + d"),

  # outputs
  verbatimTextOutput("result_ab"),
  verbatimTextOutput("result_cd"),
  verbatimTextOutput("result_merge")
)

server <- function(input, output, session) {
  # outputs
  output$result_ab <- renderPrint(ab())
  output$result_cd <- renderPrint(cd())
  output$result_merge <- renderPrint(merge())
  
  # calculations 
  ab <- reactiveVal(NULL)
  cd <- reactiveVal(NULL)

  observeEvent(input$ab,{
    ab(input$a + input$b)
  })  
  observeEvent(input$cd,{
    cd(input$c + input$d)
  })
  
  # merge of existing values
  merge <- reactive({
    merge <- c() # empty vector to be filled up
    if(!is.null(ab())){
      merge <- ab()
    }
    if(!is.null(cd())){
      merge <- c(merge, cd())
    }
    merge
  })
  
}

shinyApp(ui, server)

Upvotes: 1

starja
starja

Reputation: 10365

As long as your reactive is not expected to return NULL at some point, you can check if the return value of a reactive is not NULL:

 merge <- reactive({
    merge <- c() # empty vector to be filled up
    
    if(!is.null(ab())){
      merge <- c(merge, ab())
    }
    
    if(!is.null(cd())){
      merge <- c(merge, cd())
    }
    
    merge
  })

Upvotes: 0

Related Questions