如何根据捕获的 shinyalert 输入值打破 for 循环

How to break a for loop basing on captured shinyalert input value

我正在使用 for loop 在我闪亮的应用程序中创建多个弹出消息(使用 shinyalert包)。 如果用户单击 Cancel 作为对上一条消息的答复,我希望消息停止弹出。 下面是说明我的示例的代码示例

library(shiny)
library(shinyalert)

ui <- fluidPage(
    actionButton("run", "Run")
)

server <- function(input, output, session) {

observeEvent(input$run, {
    
    vector.elements <- c("A", "B", "C", "D", "E")
    decision <<- TRUE
    
    for (element in vector) {
    
    shinyalert(
        title = "Do you accept following element?",
        text = element,
        showCancelButton =  TRUE,
        callbackR = mycallback)
        
        mycallback <- function(value) {
            decision <<- value
        }
        
        if (decision == FALSE) {
            break
        }
    }
})
}
shinyApp(ui = ui, server = server)

如果用户点击取消按钮作为对的回答,您是否接受以下元素? A,我希望以后的消息不要弹出

如有任何提示,我们将不胜感激!

Shiny alert 似乎 运行 与循环不同步。将 print(decision) 放在 for-loop 前面。它将在控制台中显示循环 运行s 独立于用户单击警报消息。这意味着:它不适用于 for 循环或任何其他循环。只能使用Shiny提供的事件机制来完成。

下面的解决方案创建并操作了一个反应值 RequiredAnswers。对其进行任何更改都会触发闪亮的警报打开并要求用户确认 向量的第一个元素 RequiredAnswers。换句话说,它删除了刚刚回答“否”的元素。

警报的每个答案都会被 observeEvent(input$AnswerAlert, {}) 捕获。如果响应是“取消”,它会取消 RequiredAnswers 的第一个元素,从而触发下一个警报。这样我们就得到了一个循环。如果响应为“Ok”,它将清除 RequiredAnswers 并且不会触发更多警报(因为 observeEvent(RequiredAnswers(), {}) 不响应 RequiredAnswers == NULL.

缺点:如果用户点击 'Cancel' 速度非常快,Shiny 无法识别事件 observeEvent(input$AnswerAlert, {}) 不会被调用。我不能确定这是什么来源。我的猜测是 Shiny Alert 中的一个错误。

另一种方法是递归执行(请参阅文档中的“链接模态”部分)。这样,可以避免丢失的事件。

library(shiny)
library(shinyalert)

ui <- fluidPage(
  actionButton("run", "Run"),
  verbatimTextOutput("answer", placeholder = TRUE)
)

server <- function(input, output, session) {

  RecentDecision <- reactiveVal()
  RequiredAnswers <- reactiveVal()
  
  # Responds to the alert being confirmed or dismissed
  observeEvent(input$AnswerAlert, {
    if (input$AnswerAlert) {
      Answer <- RequiredAnswers()[1]
      RecentDecision(Answer)
      print(RecentDecision())
      RequiredAnswers(NULL)
    } else {
      # Remove the first item of RequiredAnswers
      # Clear it completely when the end has been reached
      if (length(RequiredAnswers()) == 1) {
        RequiredAnswers(NULL)
        RecentDecision(NULL)
      }
      else
        RequiredAnswers(RequiredAnswers()[-1])
    }
  })
  
  # Responds to changes, ignores NULL
  observeEvent(RequiredAnswers(), {
    shinyalert(
      title = "Do you accept following element?",
      text = RequiredAnswers()[1],
      showCancelButton =  TRUE,
      inputId = "AnswerAlert"  # use individual id
    )
  })
  
  # Respond to the Run button
  observeEvent(input$run, {
    # Set up the vector of desired answers
    RequiredAnswers(c("A", "B", "C", "D", "E"))
  })
  
  output$answer <- renderText({
    if (!is.null(RecentDecision()))
      RecentDecision()
    else
      "No answer, yet"
  })
}

shinyApp(ui = ui, server = server)