简体   繁体   English

闪亮:observeEvent停留在DTOutput上

[英]Shiny: observeEvent stuck on DTOutput

In the app below, I can switch back and forth between outputs generated by shiny::plotOutput and shiny::dataTableOutput . 在下面的应用程序中,我可以在shiny::plotOutputshiny::plotOutput shiny::dataTableOutput生成的输出之间来回切换。 But when I select the option "DT", which generates a table using the DT::DTOutput function, the app gets stuck: 但是,当我选择选项“ DT”(使用DT::DTOutput函数生成表)时,应用程序卡住了:

  1. I can interact with the table (good) 我可以和桌子互动(好)
  2. Clicking "Load" does nothing (not good) even though it worked perfectly when non-DT output was selected before. 单击“加载”不会执行任何操作(不好),即使在之前选择非DT输出时也可以正常运行。 Clicking "Load" should switch to selected output. 单击“加载”应切换到选定的输出。

Is this a bug in DT? 这是DT中的错误吗? Is there a workaround? 有解决方法吗?

UI: 用户界面:

library(shiny)

ui <- fluidPage(
  uiOutput("ui_select"),
  uiOutput("my_ui")
)

Server: 服务器:

server <- function(input, output) {

  output$ui_select = renderUI({
    tagList(
      selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
      actionButton("loadVal", label = "Load")
    )
  })

  observeEvent(input$loadVal, {

    val = isolate({ input$selectVal })

    output$my_output = switch(
      val,
      "gg" = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) }),
      "dt" = renderDataTable({ mtcars[1:3, 1:3] }),
      "DT" = DT::renderDT({ mtcars[1:3, 1:3] })
    )

    output$my_ui = renderUI({
      switch(
        val,
        "gg" = plotOutput("my_output"),
        "dt" = dataTableOutput("my_output"),
        "DT" = DT::DTOutput("my_output")
      )
    })

  })
}

shinyApp(ui, server)

Its generally not a good idea to render much inside the observe as a memory leak can occur. 它通常不是一个好主意,使很多内部的observe为内存泄漏可能会发生。 have a look at the example below with a bigger diamonds dataset from the ggplot2 package. 看看下面更大的示例diamonds从数据集ggplot2包。

library(shiny)
library(ggplot2)
data(diamonds)

ui <- fluidPage(
  uiOutput("ui_select"),
  uiOutput("my_ui")
)

server <- function(input, output) {

  output$ui_select = renderUI({
    tagList(
      selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
      actionButton("loadVal", label = "Load")
    )
  })

  observeEvent(input$loadVal, {

    val = isolate({ input$selectVal })

    output$gg_output = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) })
    output$dt_output = renderDataTable({ diamonds })
    output$DT_output = DT::renderDT({ diamonds })

    output$my_ui = renderUI({
      switch(
        val,
        "gg" = plotOutput("gg_output"),
        "dt" = dataTableOutput("dt_output"),
        "DT" = DT::DTOutput("DT_output")
      )
    })

  })
}

shinyApp(ui, server)

在此处输入图片说明

Also I dont think its very efficient to create objects all the time, its best to render them once and simply switch and show what is required. 我也不认为一直创建对象非常有效,最好只渲染一次并简单地切换并显示所需内容。

Proposed solution 拟议的解决方案

library(shiny)
library(shinyjs)
library(ggplot2)
data(diamonds)
outputs <- c("gg_output","dt_output","DT_output")

hideoutputs <- function(output_names){
  lapply(output_names, function(output_name){
    hide(output_name)
  })
}

ui <- fluidPage(
  useShinyjs(),
  uiOutput("ui_select"),
  plotOutput("gg_output"),
  dataTableOutput("dt_output"),
  DT::DTOutput("DT_output")
)

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

  hideoutputs(outputs)
  v <- reactiveValues(selection = "None")

  output$ui_select <- renderUI({
    tagList(
      selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
      actionButton("loadVal", label = "Load")
    )
  })

  output$gg_output <- renderPlot({ 
    qplot(cyl, drat, data = mtcars) 
  })

  output$dt_output <- renderDataTable({ 
    diamonds 
  })

  output$DT_output <- DT::renderDT({ 
    diamonds 
  })

  observeEvent(input$loadVal, {

    if(v$selection == input$selectVal){
      return()
    }

    hideoutputs(outputs)
    switch(
      input$selectVal,
      "gg" = show("gg_output"),
      "dt" = show("dt_output"),
      "DT" = show("DT_output")
    )
    v$selection <- input$selectVal
  })

}

shinyApp(ui, server)

You're essentially defining multiple elements with the same ID. 您实际上是在定义多个具有相同ID的元素。 That's invalid HTML, and is bound to result in undefined behaviour. 那是无效的HTML,势必导致未定义的行为。 Sometimes defining multiple inputs/outpust with identical IDs seems to work, but it should never be done. 有时用相同的ID定义多个输入/输出似乎可行,但是绝对不要这样做。

Giving each output its own ID solves this. 为每个输出提供自己的ID可解决此问题。

server <- function(input, output) {

    output$ui_select = renderUI({
        tagList(
            selectInput("selectVal", "Select value", choices = c("gg", "dt", "DT")),
            actionButton("loadVal", label = "Load")
        )
    })

    observeEvent(input$loadVal, {

        val = isolate({ input$selectVal })

        output$gg_output = renderPlot({ ggplot2::qplot(cyl, drat, data = mtcars) })
        output$dt_output = renderDataTable({ mtcars[1:3, 1:3] })
        output$DT_output = DT::renderDT({ mtcars[1:3, 1:3] })

        output$my_ui = renderUI({
            switch(
                val,
                "gg" = plotOutput("gg_output"),
                "dt" = dataTableOutput("dt_output"),
                "DT" = DT::DTOutput("DT_output")
            )
        })

    })
}

shinyApp(ui, server)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM