内容完成后检查 downloadHandler 的状态

问题描述 投票:0回答:1

我有一个

shiny
应用程序,可以在用户单击按钮时生成并保存报告。 我想通过更改按钮的标签和图标来显示按钮中的保存状态。

我使用

downloadButton
来允许用户指定位置和文件名。 该报告是使用
officer
保存的
print(obj, target)
Word 文档。

预期流量为:

  • 用户点击按钮
  • 按钮更改为“正在保存...”
  • 文件对话框打开
  • 用户选择文件名/位置
  • r 尝试保存文档
  • 如果保存成功(即没有错误),按钮将更改为“已保存”
  • 否则按钮会变为“保存失败”

实际流程是:

  • 用户点击按钮
  • 按钮更改为“正在保存...”
  • 按钮更改为“已保存”
  • 文件对话框打开
  • 用户选择文件名/位置
  • ...

在将状态更改为“已保存”之前,脚本不会等待用户选择文件或查看文件是否正确保存。在这种情况下,文件正确保存,但脚本在打印到目标之前无法知道这一点,并且在用户提供文件名/位置之前无法打印到目标。

如何修改此设置,使状态更改与文件是否正确保存相关?

library(shiny)
library(shinyjs)
library(officer)

ui <- fluidPage(
  useShinyjs(),  # Initialize shinyjs
  uiOutput("save_bullet_reportui")
)

server <- function(input, output, session) {
  values <- reactiveValues(
    bullet_report_status = "save"
  )
  
  observeEvent(values$bullet_report_status, {
    status <- isolate(values$bullet_report_status)
    print(paste0("status changed to: ", status))
    output$save_bullet_reportui <- renderUI({
      if(status == "save"){
        downloadButton("save_bullet_report", "Save to .docx", icon = icon("file-word"))
      }else if(status == "saving"){
        downloadButton("save_bullet_report", "Saving...", 
                       icon = icon("spinner", class = "fa-spin"))
      }else if(status == "success"){
        downloadButton("save_bullet_report", "Saved", 
                       icon = icon("check", style = "color: #00AA00"))
      }else if(status == "failed"){
        downloadButton("save_bullet_report", "Save Failed", 
                       icon = icon("exclamation-triangle", style = "color: #AA0000"))
      }
    })    
  })
  
  output$save_bullet_report <- downloadHandler(
    filename = function(){
      paste0("test_report_", Sys.Date(), ".docx")
    },
    content = function(file){
      
     values$bullet_report_status <- "saving"
        br_doc_obj <- read_docx() |> 
        body_add_par("hello world")

      tryCatch({
        print(br_doc_obj, target = file)
        values$bullet_report_status <- "success"
      }, error = function(e){
           shinyjs::delay(100, {
             values$bullet_report_status <- "failed"
             })
     })
  })
}

shinyApp(ui, server)

编辑: 代码完全按照指示工作。

print
正在执行,没有错误(因此状态立即更改为“已保存”),但与下载功能无关。
print
正在将文件保存到服务器,然后一旦
content
功能完成,downloadHandler 就会开始下载过程(即启动文件对话框)。 我将“已保存”视为“成功下载”,这不是同一件事。这仍然是一个相关的测试,但我的问题确实是,“如何测试 downloadHandler 是否正确完成下载过程,以便我可以定义状态?” 目前对流程的理解是:

  • 用户点击按钮
  • 按钮更改为“保存”
  • 文件通过
    print
  • 保存到服务器
  • 按钮更改为“已保存”
  • content
    完成——剩下的事情发生在“幕后”
  • downloadHandler
    启动文件对话框以从用户处获取下载位置和文件名
  • 文件已下载
  • [这里需要帮助看看下载是否有错误]
  • [根据结果更新状态]
r shiny
1个回答
0
投票

我原以为

updateActionButton
适用于
downloadButton
,但事实似乎并非如此。 因此,我编写了以下代码来模仿
downloadButton
,但使用
actionButton

关键思想是在一个代码块内处理更新,而不是与决斗的观察者来回跳转。

library(shiny)
library(officer)

ui <- fluidPage(
    actionButton("save_bullet_report", "Save to .docx", icon = icon("file-word"))
)

server <- function(input, output, session) {

    observeEvent(input$save_bullet_report, {

        # The following appears ineffective...
        updateActionButton(session, "save_bullet_report",
                           label = "Saving...",
                           icon = icon("spinner", class = "fa-spin"))

        # ... but this works:
        notif <- showNotification("Trying to save...", duration = NULL, type = "message")
        Sys.sleep(1) # for demo only

        br_doc_obj <- read_docx() |>
            body_add_par("hello world")

        tryCatch({
            path <- file.path(tempdir(), paste0("test_report_", Sys.Date(), ".docx"))
            # stop() # uncomment to test error

            print(br_doc_obj, target = path)
            browseURL(path)

            removeNotification(notif)
            updateActionButton(session, "save_bullet_report",
                               label = "Saved",
                               icon = icon("check", style = "color: #00AA00"))

        }, error = function(e){
            removeNotification(notif)
            updateActionButton(session, "save_bullet_report",
                               label = "Save Failed",
                               icon = icon("exclamation-triangle", style = "color: #AA0000"))
        })

    })

}

shinyApp(ui, server)

不幸的是,按钮的更新似乎只有在 R 块完成后才会生效。 因此,我不知道如何更新

actionButton
以显示工作正在进行中。 但是,
showNotification
在 R 代码的报告生成块期间完全有效。

事实上,如果你想使用

downloadButton
,你可以在代码过程中使用
showNotification
来处理多次更新。

downloadButton
的一个缺点是,如果报告生成失败,shiny仍然会让用户下载一个空文件。 但对于自制的
actionButton
观察者,只有在确定报告生成正确时才能调用
browseURL

这在本地有效。 我还没有在远程闪亮服务器部署上尝试过

browseURL
。 但我已使用
browseURL
启动从远程 RStudio 服务器的下载。

© www.soinside.com 2019 - 2024. All rights reserved.