我正试图将我闪亮的应用程序分解为模块。这是代码:
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 函数?是否有可能在闪亮的模块中捕获来自两个不同模块的事件?或者这是完全错误的方法,模块设计应该是不同的?感谢。
答案 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::show
和shinyjs::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)