我正在处理一个包含多个值框的 UI 元素。单击其中一个值框时,它会显示隐藏内容。此外,单击一个值框时,另一个先前选定的值框会返回其初始状态。如下所示:
我已经实现了这个功能。但是,它有点混乱,我担心如果大型应用程序中有多个这样的 UI 元素,管理起来会很困难。
我的实现:
library(shiny)
library(bslib)
library(shinyjs)
# Module UI
cont_box_ui <- function(id) {
ns <- NS(id)
# Value box wrapped in a div for JavaScript tracking
div(id = ns("expand_box"),
value_box(
title = "Click me",
value = "10",
theme = value_box_theme(bg = "white"),
# Hidden UI content
hidden(div(id = ns("expanded_content"),
tags$p("This is additional information."),
actionButton("btn", "Click me")
))
)
)
}
cont_box_server <- function(id) {
moduleServer(id, function(input, output, session) {
# Add on.click function which
runjs(sprintf("
document.getElementById('%s-expand_box').addEventListener('click', function() {
Shiny.setInputValue('last_clicked', %s);
});
", id, id))
})
}
ui <- page_sidebar(
sidebar = sidebar(
useShinyjs(),
# Add value box UIs
cont_box_ui(1),
cont_box_ui(2),
cont_box_ui(3)
),
mainPanel()
)
server <- function(input, output, session) {
# Add value box servers
cont_box_server(1)
cont_box_server(2)
cont_box_server(3)
# Observe for when a value box is clicked
observeEvent(input$last_clicked, {
# Store ids of all show/hide panels
panels <- c("1-expanded_content", "2-expanded_content", "3-expanded_content")
# Store ids of panels which should be collapsed (even though it's just one)
collapse <- panels[panels != sprintf("%s-expanded_content", input$last_clicked)]
# Store id of panel to expand
expand <- sprintf("%s-expanded_content", input$last_clicked)
# Hide all panels except the one which was clicked
for(this_panel in collapse){
shinyjs::hide(this_panel)
}
# Show hidden content of clicked panel
shinyjs::show(expand)
})
}
shinyApp(ui, server)
我不喜欢在我的实现中迭代除被点击的值框之外的每个值框以隐藏它们,即使我只需要隐藏之前点击的值框。有没有办法避免这种情况?
我想在模块服务器/UI 中包含显示/隐藏功能所需的所有代码,而不需要
observeEvent()
在主服务器中显示/隐藏元素。这可能吗?
我在这里的唯一目标是简化这个实现,以减少在大型 Shiny 应用程序中使用时的心理负担。