Shiny中有一个事件处理程序的多个动作按钮?

时间:2016-09-26 15:45:53

标签: r shiny

我想在页面上有一个可变数量的相同actionButton(),它们都由一个observeEvent()函数处理。

例如,在一个可变长度的表格表格中,我希望每个内部表格都有一个链接到该表格的更多信息的按钮。

在标准HTML中,您可以使用一个简单的表单来执行此操作,您可以使用隐藏的输入来指定内部表号,如下所示:

<form ...>
  <input id="table_number" type="hidden" value="1"/>
  <input type="submit" value="Examine"/>
</form>

按下按钮时,您可以检查隐藏的输入以查看它是哪一个。

有没有办法在Shiny中做到这一点?我想出的唯一解决方案是给每个actionButton()它自己的inputId。这需要为每个按钮单独的observeEvent()。这些必须提前创建,强加最多数量的按钮。

3 个答案:

答案 0 :(得分:3)

这只花了我几年时间,但我现在对这个问题有了更好的答案。您可以使用JavaScript / jQuery函数在文档中的每个按钮上放置一个on-click事件处理程序,然后使用 Shiny.onInputChange()函数传递按钮的ID({{1已经点击了Shiny代码中的单个观察者。

One observer for all buttons in Shiny using JavaScript/jQuery

上有代码示例的完整说明

答案 1 :(得分:2)

您可以使用闪亮的模块:您可以使用相同的可变数量的actionButton。这些在ab_moduleUI部分中定义。它们由自己的observeEvent处理,但只需在ab_module部分定义一次。

lapply可以创建任意数量的actionButton

编辑:您不必事先指定按钮数:使用renderUI在服务器端生成UI元素。

出于演示目的,我添加了numericInput来增加/减少要渲染的模块数量。

# UI part of the module
ab_moduleUI <- function(id){
  ns <- NS(id)
  tagList(
    fluidRow(
      actionButton(ns("btn"), paste("ActionButton", id, sep="-")),
      textOutput(ns("txt"))
    )
  )
}

# Server part of the module
ab_module <- function(input, output, session){
  observeEvent(input$btn,{
    output$txt <- renderText("More information shown")
  })
}


# UI
ui <- fluidPage(
  # lapply(paste0("mod", 1:no_btn), ab_moduleUI)
  numericInput("num", "Number of buttons to show" ,value = 5, min = 3, max = 10),
  uiOutput("ui")
)

# Server side
server <- function(input, output, session){
  observeEvent(input$num, {
    output$ui <- renderUI({
      lapply(paste0("mod", 1:input$num), ab_moduleUI)
    })

    lapply(paste0("mod", 1:input$num), function(x) callModule(ab_module, x))
  })

}

shinyApp(ui, server)

详细了解闪亮模块here

答案 2 :(得分:0)

关于使用Shiny模块回答我原来的问题......

我想要的是在页面上有多个按钮可以由单个observeEvent()处理的方法,这很容易用传统的HTML表单,如原始问题所示。

使用Shiny模块的GyD演示代码几乎解决了这个问题,但它实际上并没有返回哪个按钮被按下到主服务器。我花了很长时间,但我终于想出了如何编写一个让主服务器知道按下哪个按钮的模块:

actionInput <- function(id) {
   ns <- NS(id)
   tagList(
      textInput(ns("text"), label=NULL, value=id),
      actionButton(ns("button"), "OK")
   )
}

action <- function(input, output, session) {
   eventReactive(input$button, {
      return(input$text)
   })
}

ui <- fluidPage(fluidRow(column(4, actionInput("b1")),
                         column(4, actionInput("b2")),
                         column(4, uiOutput("result"))))

server <-function(input, output, session) {
   b1 <- callModule(action, "b1")
   observeEvent(b1(), {
      output$result = renderText(b1())
   })
   b2 <- callModule(action, "b2")
   observeEvent(b2(), {
      output$result = renderText(b2())
   })
}

shinyApp(ui = ui, server = server)

(在实际应用中,我会使textInputs不可见,因为它们只是提供按下按钮的ID。)

对于每个按钮,此解决方案仍需要主服务器中的observeEvent()。有可能以其他方式使用模块来解决问题,但我无法弄明白。

我的原始替代方案,在每个按钮的主服务器中使用单独的observeEvent(),实际上比这个演示代码的扩展对于一百个或更多按钮更简单。