闪亮模块中DT :: DTOutput中的actionButton上的Observe行为不正确

时间:2018-07-31 15:48:44

标签: shiny dt shinyjs action-button

下面的代码示例生成简单的ShinyApp,其中包含数字输入和带有行按钮的数据表。数据表中的行数与数字输入相同。此外,每个按钮都会被观察到,并在按下时产生警报。

library(shiny)
library(DT)
library(shinyjs)

exampleModuleUI <- function(id) {
    ns <- NS(id)

    DT::DTOutput(ns("table"))
}

exampleModule <- function(input, output, session, max.index) {
    ns <- session$ns

    output$table <- renderDataTable(
        data.frame(
            buttons = unlist(
                lapply(
                    1:max.index, 
                    function(index) {
                        as.character(
                            actionButton(
                                ns(as.character(index)), 
                                as.character(index)
                            )
                        )
                    }
                )
            )
        ),
        escape = FALSE, 
        style = 'bootstrap',
        extensions = 'FixedColumns',
        options = list(
            preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
            drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
        )
    )

    lapply(
        1:max.index, 
        function(index) {
            observeEvent(input[[as.character(index)]], {
                shinyjs::alert(as.character(index))
            })
        }
    )
}

ui <- fixedPage(
    useShinyjs(),
    numericInput(
        "count", 
        "Count of button in table",
        value = 3,
        min = 3, 
        max = 7, 
        step = 1
    ),
    exampleModuleUI("dt.table")
)

server <- function(input, output, session) {
    max.count <- reactive({
        input$count
    })

    observeEvent(
        max.count(), {
            callModule(exampleModule, "dt.table", max.count())
        }
    )
}

shinyApp(ui, server)

问题
如果在数字输入中首先输入“ 7”,然后输入“ 6”,然后再次输入“ 7”,则将不再观察到一个按钮。 当您再次调用某个模块时,似乎出了点问题,但是我不清楚具体原因。但是最有趣的问题是“ 如何使其工作?

1 个答案:

答案 0 :(得分:0)

那是因为您必须在绘制新表之前取消绑定。

您可以将无功导体传递到max.index,而不是多次调用模块。

我还添加了一个反应性值,该值用于收集已经存在的观察者,以免多次定义它们。

library(shiny)
library(DT)
library(shinyjs)

exampleModuleUI <- function(id) {
  ns <- NS(id)
  DT::DTOutput(ns("table"))
}

exampleModule <- function(input, output, session, max.index) {
  ns <- session$ns

  output$table <- renderDataTable(
    data.frame(
      buttons = unlist(
        lapply(
          1:max.index(), 
          function(index) {
            as.character(
              actionButton(
                ns(as.character(index)), 
                as.character(index)
              )
            )
          }
        )
      )
    ),
    escape = FALSE, 
    style = 'bootstrap',
    extensions = 'FixedColumns',
    options = list(
      preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
      drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } ')
    )
  )

  observers <- reactiveVal(NULL) # to store the existing observers

  observeEvent(max.index(), {
    runjs('Shiny.unbindAll($("#dt-table").find("table").DataTable().table().node());')
    lapply(
      setdiff(1:max.index(), observers()), 
      function(index) {
        observers(c(observers(),index)) # add index to the existing observers
        observeEvent(input[[as.character(index)]], {
          shinyjs::alert(as.character(index))
        }, ignoreInit = TRUE)
      }
    )
  })
}

ui <- fixedPage(
  useShinyjs(),
  numericInput(
    "count", 
    "Count of button in table",
    value = 3,
    min = 3, 
    max = 7, 
    step = 1
  ),
  exampleModuleUI("dt")
)

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

  max.count <- reactive({
    input$count
  })

  callModule(exampleModule, "dt", max.count)

}

shinyApp(ui, server)