rshinyobservers

Equivalent observers in Shiny apps but different behaviors


The difference between the two Shiny apps is that the first one includes

  observeEvent(
    input$alert,
    {
      flag(TRUE)
    }
  )

while this code is replaced with the following code in the second one:

  observeEvent(
    list(input$alert, input$X),
    {
      flag(TRUE)
    }, ignoreInit = TRUE
  )

where input$X is always NULL.

However the two apps have a different behavior (click several times on the button). Why? I don't understand the behavior of the second one.

library(shiny)
library(shinyWidgets)

ui <- fluidPage(
  mainPanel(
    actionButton(
      inputId = "button",
      label = "ALERT"
    )
  )
)

server1 <- function(input, output, session) {
  
  flag <- reactiveVal(NULL)
  
  observeEvent(
    input$button,
    {
      confirmSweetAlert(
        inputId = "alert",
        title = "ALERT",
        type = "error"
      )
    }
  )
  
  observeEvent(
    input$alert,
    {
      flag(TRUE)
    }
  )
  
  observeEvent(
    flag(),
    {
      flag(NULL)
      sendSweetAlert(
        title = "ALERT 2",
        type = "error"
      )
    }
  )
  
}


server2 <- function(input, output, session) {
  
  flag <- reactiveVal(NULL)

  observeEvent(
    input$button,
    {
      confirmSweetAlert(
        inputId = "alert",
        title = "ALERT",
        type = "error"
      )
    }
  )

  observeEvent(
    list(input$alert, input$X),
    {
      flag(TRUE)
    }, ignoreInit = TRUE
  )

  observeEvent(
    flag(),
    {
      flag(NULL)
      sendSweetAlert(
        title = "ALERT 2",
        type = "error"
      )
    }
  )
  
}

shinyApp(ui = ui, server = server1)
shinyApp(ui = ui, server = server2)

Solution

  • The different behaviour is caused by the fact, that list(NULL, NULL) is not NULL (resulting in flag being set to TRUE):

    > is.null(list(NULL, NULL))
    [1] FALSE
    

    and observeEvent uses ignoreNULL = TRUE by default.

    Setting ignoreNULL = FALSE in server1 results in the same behaviour as shown for server2:

    server1 <- function(input, output, session) {
      
      flag <- reactiveVal(NULL)
      
      observeEvent(
        input$button,
        {
          confirmSweetAlert(
            inputId = "alert",
            title = "ALERT",
            type = "error"
          )
        }
      )
      
      observeEvent(
        input$alert,
        {
          flag(TRUE)
        }, ignoreNULL = FALSE
      )
      
      observeEvent(
        flag(),
        {
          flag(NULL)
          sendSweetAlert(
            title = "ALERT 2",
            type = "error"
          )
        }
      )
      
    }
    

    As an alternative use c(input$alert, input$X) instead of list(input$alert, input$X) in server2:

    > is.null(c(NULL, NULL))
    [1] TRUE
    

    server2 <- function(input, output, session) {
      
      flag <- reactiveVal(NULL)
      
      observeEvent(input$button,
        {
          confirmSweetAlert(
            inputId = "alert",
            title = "ALERT",
            type = "error"
          )
        }
      )
      
      observeEvent({c(input$alert, input$X)},
        {
          flag(TRUE)
        }, ignoreInit = TRUE
      )
      
      observeEvent(
        flag(),
        {
          flag(NULL)
          sendSweetAlert(
            title = "ALERT 2",
            type = "error"
          )
        }
      )
      
    }