Estou trabalhando em um elemento de UI que contém uma série de caixas de valor. Quando uma dessas caixas de valor é clicada, ela mostra conteúdo oculto. Além disso, quando uma caixa de valor é clicada, a outra caixa de valor selecionada anteriormente volta ao seu estado inicial. Como visto aqui:
Eu fiz uma implementação funcional disso. No entanto , é um pouco bagunçado e estou preocupado que se tornará difícil de gerenciar se eu tiver vários elementos de UI como esses dentro de um aplicativo grande.
Minha implementação:
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)
Não gosto que, na minha implementação, eu itero sobre cada caixa de valor diferente daquela que foi clicada para ocultá-las, embora eu só precise ocultar a caixa de valor clicada anteriormente. Pode haver uma maneira de evitar isso?
Gostaria de conter todo o código necessário para essa funcionalidade de mostrar/ocultar dentro do servidor/UI do módulo, sem a necessidade de um
observeEvent()
dentro do servidor principal para mostrar/ocultar elementos. Isso é possível?
Meu único objetivo aqui é simplificar essa implementação para reduzir a carga mental quando ela for usada em um grande aplicativo Shiny.