janosdivenyi
janosdivenyi

Reputation: 3236

Use shinyalert to confirm data update

I would like to make the data behind my shiny refreshable upon user's request. However, as the refresh takes several minutes, I would like to warn the user before actually starting the process and allow them to cancel.

I use the super shinyalert package by @deanattali to setup the alert. Here is a small reproducible example. Think of data(mtcars) as fetching some data, and the average calculation as some data processing, both of which takes some time.

library(shiny)
library(shinyalert)
library(data.table)

ui <- bootstrapPage(
    useShinyalert(),
    actionButton("refresh", "Refresh"),
    dataTableOutput("table")
)

server <- function(input, output) {
    observeEvent(input$refresh, {
        shinyalert("You are abouto to refresh data...", showCancelButton = TRUE)
    })

    aggregated_data <- eventReactive(input$shinyalert, {
        message("reload data")
        data(mtcars)
        as.data.table(mtcars)[, .(avg_speed = mean(mpg)), by = cyl]
    }, ignoreNULL = FALSE)

    output$table <- renderDataTable(
        aggregated_data()
    )
}

shinyApp(ui, server)

However, it does not work as I want. It reloads the data whenever input$shinyalert changes, not when the user clicked "OK" (I know this is the expected functionality, I just don't know how to achieve the functionality I want). How can I rewrite this to recalculate aggregated_data reactive only if the input$shinyalert changed to TRUE?

(I tried a simple if statement within the eventReactive but it does not return anything if the condition evaluates to FALSE.)

Upvotes: 2

Views: 1656

Answers (1)

Thomas
Thomas

Reputation: 1302

You are using eventReactive the wrong way. This isn't working as expected because shinyalert returns FALSE if you click cancel and thus, triggers eventReactive - see shinyalert github readme

When there is no input field in the modal, the value of the modal is TRUE if the user clicked the “OK” button, and FALSE if the user clicked the “Cancel” button.

Try reactiveValues instead of eventReactive and use req()inside the observer which ignores FALSE values

server <- function(input, output) {
  observeEvent(input$refresh, {
    shinyalert("You are abouto to refresh data...", showCancelButton = TRUE)
  })

  aggregated <- reactiveValues()

  observe({
    req(input$shinyalert)
    message("reload data")
    data(mtcars)
    aggregated$data <- as.data.table(mtcars)[, .(avg_speed = mean(mpg)), by = cyl]
  })

  output$table <- renderDataTable(
    aggregated$data
  )
}

Also, if you like to set up the ignoreNULL = FALSE again, you can specify this with the creation of aggregated

Upvotes: 2

Related Questions