R shiny:在功能运行时显示“loading ...”消息

时间:2013-06-26 16:26:13

标签: r shiny

我使用Shiny GUI R包。我正在寻找一种在按下actionButton后显示“loading ...”等消息的方法。该函数需要几分钟才能执行,因此我需要以某种方式通知用户按钮实际触发了某个事件。现在server.R代码如下所示:

DATA <- reactive({
  if(input$DownloadButton>0) {
    RunDownload()
  } else {
    NULL
  }
})

output$Download <- renderText({
  if(NROW(DATA())>0) {
    paste0(Sys.time(),": ",NROW(DATA()), " items downloaded")
  } else {
    ''
  }
})

actionButton()是一个从互联网下载数据的功能。 input$DownloadButton是actionButton。因此,在按下按钮后,用户等待几分钟,然后才会看到一条消息,表明下载成功。我想在按下actionButton之后显示消息“正在加载...”,然后在执行结束时显示另一条消息,如paste0(Sys.time(),": ",NROW(DATA()), " items downloaded")

6 个答案:

答案 0 :(得分:32)

我已经使用了比之前发布的更简单,更可靠的方式。

的组合
tags$style(type="text/css", "
           #loadmessage {
             position: fixed;
             top: 0px;
             left: 0px;
             width: 100%;
             padding: 5px 0px 5px 0px;
             text-align: center;
             font-weight: bold;
             font-size: 100%;
             color: #000000;
             background-color: #CCFF66;
             z-index: 105;
           }
  ")

conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                 tags$div("Loading...",id="loadmessage")
)

示例:

runApp(list(
  ui = pageWithSidebar(
      headerPanel("Test"),
         sidebarPanel(
           tags$head(tags$style(type="text/css", "
             #loadmessage {
               position: fixed;
               top: 0px;
               left: 0px;
               width: 100%;
               padding: 5px 0px 5px 0px;
               text-align: center;
               font-weight: bold;
               font-size: 100%;
               color: #000000;
               background-color: #CCFF66;
               z-index: 105;
             }
          ")),
           numericInput('n', 'Number of obs', 100),
           conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                            tags$div("Loading...",id="loadmessage"))
         ),
         mainPanel(plotOutput('plot'))
  ),
  server = function(input, output) {
    output$plot <- renderPlot({ Sys.sleep(2); hist(runif(input$n)) })
  }
))

标签$ head()不是必需的,但将所有样式保留在head标签内是一种很好的做法。

答案 1 :(得分:4)

我通过将以下代码添加到sidebarPanel()来解决了这个问题:

HTML('<script type="text/javascript">
        $(document).ready(function() {
          $("#DownloadButton").click(function() {
            $("#Download").text("Loading...");
          });
        });
      </script>
')

答案 2 :(得分:4)

非常简单,您可以在函数的开头showModal()和结尾的removeModal()使用内置的闪亮函数。如果您删除页脚,则无法从中点击该模式。

示例:

observeEvent(input$button, {
     showModal(modalDialog("Doing a function", footer=NULL))
     #Do the stuff here....
     #...
     #...
     #Finish the function
     removeModal()
})

答案 3 :(得分:3)

您可以使用ShinyJS:https://github.com/daattali/shinyjs

按下actionButton后,您可以轻松切换显示&#34; loading ...&#34;的文本组件,当计算完成后,您可以将此组件切换为隐藏。

答案 4 :(得分:2)

我找到了一个解决方案,对我来说很好。我正在使用Bootstrap模式。它会在函数执行开始时显示,并在结束时再次隐藏。

  

modalBusy&lt; - function(id,title,...){

 msgHandler =  singleton(tags$head(tags$script('Shiny.addCustomMessageHandler("jsCode",
                                            function(message) {
                                              console.log(message)
                                              eval(message.code);
                                            });'
                                            )
                                )
                      )

 label_id = paste(id, "label", sep='-')
 modal_tag <- div(id=id, 
               class="modal hide fade", 
               "aria-hidden"=FALSE, 
               "aria-labelledby"=label_id, 
               "role"="dialog", 
               "tabindex"="-1",
               "data-keyboard"=FALSE,
               "data-backdrop"="static")
 header_tag <- div(class="modal-header",
                h3(id=label_id, title))
 body_tag <- div(class="modal-body",
              Row(...))   
 footer_tag <- div(class="modal-footer")
 modal_tag <- tagAppendChildren(modal_tag, header_tag, body_tag, footer_tag)
 tagList(msgHandler, modal_tag) 
}

要显示和隐藏它,请使用功能

showModal <- function(id,session) {
  session$sendCustomMessage(type="jsCode",
                            list(code= paste("$('#",id,"').modal('show')"
                                             ,sep="")))
}

hideModal <- function(id,session) {
  session$sendCustomMessage(type="jsCode",
                            list(code= paste("$('#",id,"').modal('hide')"
                                             ,sep="")))
}

在函数调用之前调用showModal函数,之后调用hideModal函数!

希望这有帮助。

的Seb

答案 5 :(得分:1)

虽然这个问题很老了,但我认为它仍然相关。我提供了另一种解决方案,它在按钮上显示活动指示器,在按钮标签旁边开始一个漫长的过程。

Button with an activity indicator

我们需要一个在 span 中带有标签的操作按钮以及识别该标签的某种方式。

actionButton("btnUpdate", span("Update", id="UpdateAnimate", class=""))

我们还需要一些可以添加到按钮标签的 CSS 动画,例如像这样:

            tags$head(tags$style(type="text/css", '
            .loading {
                display: inline-block;
                overflow: hidden;
                height: 1.3em;
                margin-top: -0.3em;
                line-height: 1.5em;
                vertical-align: text-bottom;
                box-sizing: border-box;
            }
            .loading.dots::after {
                text-rendering: geometricPrecision;
                content: "⠋\\A⠙\\A⠹\\A⠸\\A⠼\\A⠴\\A⠦\\A⠧\\A⠇\\A⠏";
                animation: spin10 1s steps(10) infinite;
                animation-duration: 1s;
                animation-timing-function: steps(10);
                animation-delay: 0s;
                animation-iteration-count: infinite;
                animation-direction: normal;
                animation-fill-mode: none;
                animation-play-state: running;
                animation-name: spin10;
            }
            .loading::after {
                display: inline-table;
                white-space: pre;
                text-align: left;
            }
            @keyframes spin10 { to { transform: translateY(-15.0em); } }
            '))

现在我们可以使用 shinyjs 来操作 span 类,它动态地在按钮标签后面添加动画。我们在用户按下按钮时添加动画:

    observeEvent(input$btnUpdate, { # User requests update
        # ... 

        shinyjs::addClass(id = "UpdateAnimate", class = "loading dots")
        shinyjs::disable("btnUpdate")
        
        # ...
    })

当操作完成后,我们可以从span中移除类并结束动画:

    output$distPlot <- renderPlot({
        # ...
        
        Sys.sleep(1) # just for show, you probably want to remove it in a real app
        # Button settings        
        shinyjs::enable("btnUpdate")
        shinyjs::removeClass(id = "UpdateAnimate", class = "loading dots")

        # ...
    })

full code of the sample app is available as gist on GitHub