Shiny应用:点击actionButton后触发shinycustomloader加载效果
解决Shiny应用中仅点击按钮触发加载动画且每次点击都生效的问题
我明白你的问题:你希望只有在用户点击Submit按钮时才显示加载界面,而且每次点击都要触发加载动画,而不是只第一次有效。之前用conditionalPanel("input.submit==1")的问题在于,input.submit的值是累加的——第一次点击是1,第二次是2,第三次是3……所以后续点击时条件不再满足,加载界面就不显示了。
下面是两种可行的解决方案,都能实现你的需求:
方案1:使用reactiveVal跟踪加载状态
这种方法通过一个响应式变量来控制加载状态,每次点击按钮时先标记为"加载中",数据处理完成后标记为"加载完成",这样就能确保每次点击都触发加载动画。
修改后的完整代码
ui.R
library(shiny) library(shinydashboard) library(DT) library(shinycustomloader) dashboardPage( dashboardHeader(), dashboardSidebar( selectizeInput("file", "Select File", c("fileA", "fileB")), actionButton("submit", "Submit") ), dashboardBody( fluidRow( box( h2("My Data"), # 根据加载状态显示不同内容 conditionalPanel( condition = "output.isLoading", div(style = 'overflow-x: scroll', withLoader(DT::dataTableOutput('mytable'), type = "html", loader = "loader1")) ), conditionalPanel( condition = "!output.isLoading && output.hasData", div(style = 'overflow-x: scroll', DT::dataTableOutput('mytable')) ), width = 12 ) ) ) )
server.R
library(shiny) library(shinydashboard) library(DT) shinyServer(function(input, output, session) { # 初始化响应式变量:跟踪加载状态和是否有数据 is_loading <- reactiveVal(FALSE) has_data <- reactiveVal(FALSE) matched_df <- reactiveVal(NULL) # 点击Submit按钮时触发 observeEvent(input$submit, { # 标记为加载中 is_loading(TRUE) has_data(FALSE) # 模拟数据处理(替换成你的实际代码) Sys.sleep(2) # 模拟耗时操作 file_name <- req(input$file) # open_file <- read_excel(paste0("input_files/", file_name)) # 这里替换成你的数据处理逻辑 temp_df <- data.frame(A = c(1, 2, 3, 4), B = c("A", "B", "C", "D")) # 处理完成后更新数据,标记加载完成 matched_df(temp_df) is_loading(FALSE) has_data(TRUE) }) # 为UI的conditionalPanel提供输出值 output$isLoading <- reactive({ is_loading() }) outputOptions(output, "isLoading", suspendWhenHidden = FALSE) output$hasData <- reactive({ has_data() }) outputOptions(output, "hasData", suspendWhenHidden = FALSE) # 渲染数据表 output$mytable = DT::renderDataTable({ req(matched_df()) matched_df() }) })
方案2:直接控制withLoader的显示(更简洁)
另一种方法是利用shinycustomloader的condition参数,结合按钮点击的次数来触发加载,同时确保每次点击都能重新触发。
修改后的UI部分
dashboardBody( fluidRow( box( h2("My Data"), div(style = 'overflow-x: scroll', withLoader( DT::dataTableOutput('mytable'), type = "html", loader = "loader1", # 条件:按钮点击次数大于0,且数据表正在渲染 condition = "input.submit > 0 && !output.mytable" ) ), width = 12 ) ) )
对应的Server调整
只需要确保每次点击按钮时,数据表的渲染会重新触发(你的现有代码已经做到了,不过建议把selected改成reactiveVal,避免在observeEvent里定义reactive):
shinyServer(function(input, output, session) { selected <- reactiveVal(NULL) observeEvent(input$submit, { # 模拟数据处理 Sys.sleep(2) matched_df <- data.frame(A = c(1, 2, 3, 4), B = c("A", "B", "C", "D")) selected(matched_df) }) output$mytable = DT::renderDataTable({ req(selected()) selected() }) })
关键说明
- 方案1的优势是更灵活,可以精确控制加载状态和空白界面的显示逻辑;
- 方案2更简洁,利用
shinycustomloader自带的condition参数,不需要额外的reactiveVal; - 两种方案都解决了
input.submit累加导致的条件失效问题,确保每次点击按钮都会触发加载动画。
内容的提问来源于stack exchange,提问作者Kasia Kulma
相关产品推荐
相关产品推荐

