如何在observeEvent中使用两次updateActionButton

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

我正在编写一个闪亮的应用程序,它会在按下按钮时生成一些绘图。当用户按下按钮时计算开始,我想在按下按钮后更新按钮的标签以显示当前正在进行计算。计算完成后,应恢复到“默认”状态。我认为这很容易用

updateActionButton
做到,但不知何故我无法让它工作。这是一个可重现的小例子。

if (interactive()) {
  
  ui <- fluidPage(
    actionButton("update", "Do calculation"),
  )
  
  server <- function(input, output, session) {
    observeEvent(input$update, {
      # Change the button label
      updateActionButton(session, "update", label = "Running calculation")
      
      # This is a random calculation which takes a few seconds as a placeholder.
      result <- 0
      for (i in 1:5000000) {
        result <- result + sqrt(i)
      }
      
      updateActionButton(session, "update", label = "finished calculation") 
    })
  }
  
  shinyApp(ui, server)
}

看起来它只是跳过了第一个

updateActionButton
调用...... 非常感谢任何对我做错的事情的见解!

干杯!

javascript r shiny shinydashboard
2个回答
3
投票

发生了什么事?

来自

?updateActionButton

输入更新器函数向客户端发送一条消息,告诉它更改输入对象的设置。 所有观察者(包括输出)运行完毕后,消息被收集并发送。

这意味着当您单击按钮时,只有在

for
循环完成后才会发送更新。

由于您尝试两次更新按钮的标签,因此仅将最后一次更新发送到客户端。

有多种解决方案,我将重点介绍两个最简单的解决方案:

解决方案1

设置按钮的

onclick
属性。

这样,您就可以避免需要与服务器进行通信来更新 UI。服务器需要做的就是在计算完成后提醒客户端。

library(shiny)  
ui <- fluidPage(
  actionButton(
    "update",
    "Do calculation",
    onclick = "$('#update').html('running...')"
  ),
)

server <- function(input, output, session) {
  observeEvent(input$update, {
    # This is a random calculation which takes a few seconds as a placeholder.
    result <- 0
    for (i in 1:5000000) {
      result <- result + sqrt(i)
    }
    
    updateActionButton(session, "update", label = "finished calculation")
  })
}

shinyApp(ui, server)

解决方案2

使用

{shinyFeedback}

这样,您就可以避免像上面的解决方案 1 中那样编写临时内联 js。您还会在按钮上看到一个漂亮的旋转器。

library(shiny)
library(shinyFeedback)
ui <- fluidPage(
  useShinyFeedback(),
  loadingButton(
    inputId = "update",
    label = "Do calculation",
    loadingLabel = "running..."
  ),
)

server <- function(input, output, session) {
  observeEvent(input$update, {
    # This is a random calculation which takes a few seconds as a placeholder.
    result <- 0
    for (i in 1:5000000) {
      result <- result + sqrt(i)
    }
    resetLoadingButton(inputId = "update")
  })
}

shinyApp(ui, server)

0
投票

在 Mwavu 的帮助下,我成功地完成了我正在尝试的事情。虽然说实话,我不太明白它为什么有效,如果有人能向我解释它为什么有效,我将不胜感激。

library(shiny)

ui <- fluidPage(
  loadingButton("renderButton", "Render Plot"),
  plotOutput("myPlot"),
  textOutput("renderStatus") #if i remove this, the code doesnt work
)

server <- function(input, output, session) {
  rendered <- reactiveVal(FALSE)
  
  observeEvent(input$renderButton, {
    rendered(FALSE)  # Reset the rendered status
    output$myPlot <- renderPlot({
      # Your plotting code here
      plot(runif(100000), runif(100000), main = "New Plot") # random plot which takes  a few seconds to render
      rendered(TRUE)  # Mark the plot as rendered
    })
  })
  
  output$renderStatus <- reactive({ # <- if I remove the output$renderStatus the code doesnt work anymore (it is stuck in the "loading" annimation)
    if (rendered()) {
      resetLoadingButton(inputId = "renderButton")
    } 
  })
}

shinyApp(ui, server)

具体来说,我不明白为什么有必要包括

textOutput("renderStatus")
output$renderStatus
。我认为有这个代码块就足够了

reactive({ 
    if (rendered()) {
      resetLoadingButton(inputId = "renderButton")
    } 
  })

触发按钮的默认状态。

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