从两个不同的模块捕获事件

时间:2018-04-19 22:11:19

标签: r shiny

我正试图将我闪亮的应用程序分解为模块。这是代码:

library(shiny)
library(plotly)

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

  tagList(
        checkboxInput(inputId = ns("select_dynamic_date_range"),
                      label = "enable date range",
                      value = FALSE,
                      width = NULL),

        uiOutput(outputId = ns("dynamic_date_range_ui"))
  )
}


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

  tagList(
        plotlyOutput(outputId = ns("distPlot"))
  )
}



testModule <- function(input, output, session) {
    output$distPlot <- renderPlotly({
        # PRINT TO CONSOLE
        print(paste("dynamic_date_range:", input$dynamic_date_range));
        print(paste("select_dynamic_date_range:", input$select_dynamic_date_range));


        df <- data.frame(a=1:10, b=1:10)
        p <- ggplot (df, aes(x=a, y=b)) + geom_point()
        ggplotly(p)
    });


    output$dynamic_date_range_ui <- renderUI({
      if (is.null(input$select_dynamic_date_range)){
        return();
      }

      if (input$select_dynamic_date_range){
        dateRangeInput(inputId = "dynamic_date_range",
                        label = "date range:",
                        start = Sys.Date() - 1,
                        end = Sys.Date() + 2)
      }
      else{
        return();
      }
    });
}



# Define UI for dataset viewer app ----
ui <- fluidPage(
  # App title ----
  titlePanel("Shiny Text"),

  # Sidebar layout with a input and output definitions ----
  sidebarLayout(

    # Sidebar panel for inputs ----
    sidebarPanel(
        testModuleUI("class")
    ),

    # Main panel for displaying outputs ----
    mainPanel(
        # plotlyOutput(outputId = "distPlot")
        testModulePlotOutput("class")
    )
  )
)

server <- function(input, output, session) {
  callModule(testModule, "class")
}

shinyApp(ui, server)

我的目标是动态(基于 checkboxInput 元素)创建 dateRangeInput 元素,然后在创建绘图时使用此 dateRangeInput 中的值(此这只是一个简化的例子,所以我在绘图创建过程中并没有真正使用 dateRangeInput ,但我真正需要的第一件事就是将值从 dateRangeInput 传递给 renderPlotly < / strong>功能)。我做了类似的事情before,它工作得很好。我在这里遇到的一个问题是变量 dynamic_date_range 永远不会从 dateRangeInput 元素中获取正确的值。如果我理解正确的闪亮和模块的哲学,那么问题是我有两个具有相同ID的元素: testModuleUI testModulePlotOutput ,(两者都有ID名称)。我一直在考虑其中一个元素的不同类名,但在这种情况下是否可以正确使用 callModule 函数?是否有可能在闪亮的模块中捕获来自两个不同模块的事件?或者这是完全错误的方法,模块设计应该是不同的?感谢。

1 个答案:

答案 0 :(得分:0)

每当在闪亮模块中使用renderUI时,您必须明确地传递名称空间函数ns,以确保创建的HTML元素使用模块前缀。

output$dynamic_date_range_ui <- renderUI({
  req(input$select_dynamic_date_range)
  dateRangeInput(inputId = session$ns("dynamic_date_range"),  ## add ns here
                 label = "date range:",
                 start = Sys.Date() - 1,
                 end = Sys.Date() + 2)
});

shiny modules article on rsudio.com中记录了此行为。

  

在模块内部,您可能想要使用uiOutput / renderUI。如果你的renderUI块本身包含输入/输出,你需要使用ns()来包装你的ID参数,

通过此更改,该应用似乎现在正常工作。

只要没有名称共谋(例如,如果两者都使用ns("plot")),在同一模块上有两个不同的UI部分就不成问题了。对于具有默认UI和辅助可选UI的模块,我经常使用它:例如“详细信息视图”。有关示例,请参阅here

旁注

从概念的角度来看,我建议您在这种情况下使用shinyjs::showshinyjs::hide(或conditionalPanel)代替renderUI来更新现有元素DOM。这在内部模块中使用也更方便,因为与renderUI不同,show/hide函数默认遵循命名空间。这是一个例子

library(shiny)
library(plotly)
library(shinyjs)

testModuleUI <- function(id) {
  ns <- NS(id)
  tagList(
    useShinyjs(),
    checkboxInput(
      inputId = ns("select_dynamic_date_range"),
      label = "enable date range",
      value = FALSE,
      width = NULL
    ),
    hidden(dateRangeInput(
      inputId = ns("dynamic_date_range"),
      label = "date range:",
      start = Sys.Date() - 1,
      end = Sys.Date() + 2
    ))
  )
}

testModulePlotOutput <- function(id) {
  ns <- NS(id)
  tagList(
    plotlyOutput(outputId = ns("distPlot"))
  )
}

testModule <- function(input, output, session) {
  observeEvent(input$select_dynamic_date_range, {
    switch(
      input$select_dynamic_date_range + 1,
      hide("dynamic_date_range"),
      show("dynamic_date_range")
    )
  })

  dateRange <- reactive({
    switch(
      input$select_dynamic_date_range + 1,
      input$dynamic_date_range,
      "daterange not in use"
    )
  })

  output$distPlot <- renderPlotly({
    # PRINT TO CONSOLE
    print(paste("dynamic_date_range:", dateRange()));
    print(paste("select_dynamic_date_range:", input$select_dynamic_date_range));

    df <- data.frame(a=1:10, b=1:10)
    ggplot (df, aes(x=a, y=b)) + geom_point()
  });
}

ui <- fluidPage(
  titlePanel("Shiny Text"),
  sidebarLayout(
    sidebarPanel(
      testModuleUI("class")
    ),
    mainPanel(
      testModulePlotOutput("class")
    )
  )
)

server <- function(input, output, session) {
  callModule(testModule, "class")
}

shinyApp(ui, server)