(代码跟在问题描述之后)
我正在使用 Shiny 制作一个 Web 应用程序,而我正在执行的一些 R 命令需要几分钟才能完成。我发现我需要向用户提供一些表明 Shiny 正在工作的指示,否则他们会不断更改我在侧面板中提供的参数,这只会导致 Shiny 在初始运行完成后反应性地重新开始计算。
因此,我创建了一个条件面板,显示一条“正在加载”消息(称为模式),其中包含以下内容(感谢 Shiny Google 小组的 Joe Cheng 的条件语句):
# generateButton is the name of my action button
loadPanel <- conditionalPanel("input.generateButton > 0 && $('html').hasClass('shiny-busy')"),
loadingMsg)
如果用户保持在当前选项卡上,这将按预期工作。但是,用户可以切换到另一个选项卡(其中可能包含一些需要运行一段时间的计算),但是加载面板会立即出现和消失,而 R 会在计算中突然消失,然后仅在之后刷新内容它完成了。
由于这可能难以想象,我提供了一些代码在下面运行。您会注意到单击按钮开始计算将产生一个很好的加载消息。但是,当您切换到选项卡 2 时,R 开始运行一些计算,但无法显示加载消息(也许 Shiny 没有注册为忙?)。如果再次按下按钮重新开始计算,加载屏幕将正确显示。
我希望在切换到正在加载的选项卡时出现加载消息!
用户界面
library(shiny)
# Code to make a message that shiny is loading
# Make the loading bar
loadingBar <- tags$div(class="progress progress-striped active",
tags$div(class="bar", style="width: 100%;"))
# Code for loading message
loadingMsg <- tags$div(class="modal", tabindex="-1", role="dialog",
"aria-labelledby"="myModalLabel", "aria-hidden"="true",
tags$div(class="modal-header",
tags$h3(id="myModalHeader", "Loading...")),
tags$div(class="modal-footer",
loadingBar))
# The conditional panel to show when shiny is busy
loadingPanel <- conditionalPanel(paste("input.goButton > 0 &&",
"$('html').hasClass('shiny-busy')"),
loadingMsg)
# Now the UI code
shinyUI(pageWithSidebar(
headerPanel("Tabsets"),
sidebarPanel(
sliderInput(inputId="time", label="System sleep time (in seconds)",
value=1, min=1, max=5),
actionButton("goButton", "Let's go!")
),
mainPanel(
tabsetPanel(
tabPanel(title="Tab 1", loadingPanel, textOutput("tabText1")),
tabPanel(title="Tab 2", loadingPanel, textOutput("tabText2"))
)
)
))
服务器.R
library(shiny)
# Define server logic for sleeping
shinyServer(function(input, output) {
sleep1 <- reactive({
if(input$goButton==0) return(NULL)
return(isolate({
Sys.sleep(input$time)
input$time
}))
})
sleep2 <- reactive({
if(input$goButton==0) return(NULL)
return(isolate({
Sys.sleep(input$time*2)
input$time*2
}))
})
output$tabText1 <- renderText({
if(input$goButton==0) return(NULL)
return({
print(paste("Slept for", sleep1(), "seconds."))
})
})
output$tabText2 <- renderText({
if(input$goButton==0) return(NULL)
return({
print(paste("Multiplied by 2, that is", sleep2(), "seconds."))
})
})
})