资讯专栏INFORMATION COLUMN

Shiny进阶:Busy Button

seasonley / 2453人阅读

摘要:当点击一个按钮后,按钮状态转为,同时显示处于计算状态计算成功后,返回执行成功额标识计算失败时,返回具体的失败信息。源代码的链接请点这里本文对这段代码进行详细地解读,需要读者有一定的和基础。

背景

在一个Shiny App中,如果点击一个按钮,往往意味着一些R代码会被执行。如果这段代码执行时间很短,用户体验不会受到影响;如果这段代码执行时间很长,界面上如果不提供给用户一些即时的反馈,就会让用户感到困惑。

本文从Github上找到了作者daattali的一个作品,专门用来提升长时运算按钮的点击体验。当点击一个按钮后,按钮状态转为disabled,同时显示处于计算状态;计算成功后,返回执行成功额标识;计算失败时,返回具体的失败信息。源代码的链接请点这里

本文对这段代码进行详细地解读,需要读者有一定的HTML和shinyjs基础。

界面增强
withBusyIndicatorUI <- function(button) {
  id <- button[["attribs"]][["id"]]  # 使用str(actionButton("test", "test"))查看Button的结构,是一个长度为3的list,其中一个元素是名为attribs的list,里面包含id、type和class属性
  div(
    `data-for-btn` = id, # 为div创建一个attribute,取值为button id,这样方便CSS Selector对其进行查询
    button, # 等价于 
    span(
      class = "btn-loading-container",
      hidden(
        strong("loading...", class = "btn-loading-indicator"),,
        icon("check", class = "btn-done-indicator")
      )
    ), # 内联元素,会跟在button的右侧显示,初始状态为隐藏,用于显示正在执行和执行成功
    hidden(
      div(class = "btn-err",
          div(icon("exclamation-circle"),
              tags$b("Error: "),
              span(class = "btn-err-msg")
          )
      )
    ) # 块级元素,会在button的下侧显示,初始状态为隐藏,用于显示执行错误的消息
  )
}
后端处理
withBusyIndicatorServer <- function(buttonId, expr) {
  # UX stuff: show the "busy" message, hide the other messages, disable the button
  # 构造CSS选择器,根据attribute定位按钮,根据class获取按钮所处的状态
  loadingEl <- sprintf("[data-for-btn=%s] .btn-loading-indicator", buttonId) 
  doneEl <- sprintf("[data-for-btn=%s] .btn-done-indicator", buttonId)
  errEl <- sprintf("[data-for-btn=%s] .btn-err", buttonId)
  # 使按钮失效
  shinyjs::disable(buttonId)
  # 显示正在执行部分
  shinyjs::show(selector = loadingEl)
  # 隐藏执行成功部分
  shinyjs::hide(selector = doneEl)
  # 隐藏执行失败部分
  shinyjs::hide(selector = errEl)
  # 执行完成后需要调用的函数:使按钮有效,隐藏正在执行部分
  on.exit({
    shinyjs::enable(buttonId)
    shinyjs::hide(selector = loadingEl)
  })
  
  # Try to run the code when the button is clicked and show an error message if
  # an error occurs or a success message if it completes
  tryCatch({
    # 执行按钮点击后的expr
    value <- expr
    # 显示执行成功
    shinyjs::show(selector = doneEl)
    # 延时两秒后,隐藏执行成功
    shinyjs::delay(2000, shinyjs::hide(selector = doneEl, anim = TRUE, animType = "fade",
                     time = 0.5))
    # 返回执行结果
    value
  }, error = function(err) { errorFunc(err, buttonId) })
}

errorFunc <- function(err, buttonId) {
  errEl <- sprintf("[data-for-btn=%s] .btn-err", buttonId)
  errElMsg <- sprintf("[data-for-btn=%s] .btn-err-msg", buttonId)
  errMessage <- err$message
  shinyjs::html(html = errMessage, selector = errElMsg)
  shinyjs::show(selector = errEl, anim = TRUE, animType = "fade")
}
Demo
library(shiny)
library(shinyjs)

ui <- fluidPage(
  useShinyjs(),
  tags$style(appCSS),
  selectInput("select", "Select an option",
              c("This one is okay" = "ok",
                "This will give an error" = "error")),
  
  # Wrap the button in the function `withBusyIndicatorUI()`
  withBusyIndicatorUI(
    actionButton(
      "uploadFilesBtn",
      "Process data",
      class = "btn-primary"
    )
  )
)

server <- function(input, output, session) {
  observeEvent(input$uploadFilesBtn, {
    # When the button is clicked, wrap the code in a call to `withBusyIndicatorServer()`
    withBusyIndicatorServer("uploadFilesBtn", {
      Sys.sleep(1)
      if (input$select == "error") {
        stop("choose another option")
      }
    })
  })
}

shinyApp(ui = ui, server = server)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83944.html

相关文章

  • Docker-Shiny使用笔记1

    摘要:之前只是听说是一个容器技术,微型虚拟机,然后在这之前并没有接触过,所以不得不硬着头皮看英文的帮助文档,借助的这个好用来做笔记,充当专栏文章。英文好的同学可以按照这个教程来下载问题我默认看这篇文章的都是党。。 写在前面的话 在HarryZhu写的系列的docker文章后,我也开始心动了,准备尝试一下。周末在家下了半天,终于下载成功了,然后也跑起来。Docker之前只是听说是一个容器技术,...

    darkerXi 评论0 收藏0
  • [原]打造数据产品的快速原型:Shiny的Docker之旅

    摘要:使得非传统程序员的使用者不必依赖于前端后端工程师就可以自己依照业务完成一些简单的数据可视化工作,快速验证想法的可靠性。本文以上的的新主机为例。 概述 本文将介绍如何通过Docker+Shiny-Server技术极速打造Web开发,并通过实战案例进行演示。 为什么使用Shiny Shiny是R中的一种Web开发框架,使得R的使用者不必太了解css、js只需要了解一些html的知识就可以快...

    seal_de 评论0 收藏0
  • [原]文档定义应用:数据科学的文档革命

    摘要:对于数据科学的研究可以说已经是本文我将介绍如何以文档定义应用的方式成为数据科学中的标准交付。参考前文解密的数据科学部门如果构建知识仓库,作为一个谢大大的死忠,我很自然选择了作为我文档输出的首选工具。 showImg(https://segmentfault.com/img/remote/1460000006760433?w=423&h=426); 概述 随着近年来,Rstudio 通过...

    wh469012917 评论0 收藏0
  • [原] 容器定义应用:数据科学的容器革命

    摘要:概述随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自的容器化技术。本文将介绍利用容器技术如何加速数据科学在生产环境中的实际应用。 showImg(https://segmentfault.com//img/bVxzYL); 概述 随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自Doc...

    alin 评论0 收藏0
  • [原] 容器定义应用:数据科学的容器革命

    摘要:概述随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自的容器化技术。本文将介绍利用容器技术如何加速数据科学在生产环境中的实际应用。 showImg(https://segmentfault.com//img/bVxzYL); 概述 随着容器化技术的兴起,数据科学现在最大的一场运动已经不是由一个新的算法或者统计方法发起的了,而是来自Doc...

    novo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<