Я пытаюсь создать динамический интерфейс с произвольным количеством дочерних элементов.Я сделал это, создав родительский модуль (modOperation), который рекурсивно вызывает дочерний модуль (modOperationElement).Пока что интерфейс работает должным образом, но я не могу понять, как вернуть входные $ data из дочернего модуля (ов) в родительский (и в конечном итоге мне нужно будет передать это обратно в блестящую функцию сервера).
В приведенном ниже примере данные, возвращаемые в значениеtivtiveValue operation_rvs[["operation"]]
и renderPrinted в textOutput(ns("testOutput"))
, не обновляются при изменении значений в дочернем модуле.Из-за этого значения сбрасываются при создании или удалении дочерних модулей.
Идентичный подход работает, когда я опускаю родительский модуль и просто перемещаю код из modOperation в server ().
Я был бы рад услышать обо всем очевидном, что я пропустил, что нарушает этот код, или, альтернативно, более эффективный подход к этой общей проблеме (например, такой подход затрудняет удаление дочернего модуля сactionButton внутри самого дочернего модуля)
library(shiny)
library(data.table)
library(shinydashboard)
# Modules ----
## modOperationElement ----
modOperationElementUI_List = function (operationList) {
uiList = lapply(
1:(length(operationList) %>% as.integer),
function(i) {
modOperationElementUI(i, operationList[[i]])
}
)
return (uiList)
}
modOperationElementUI = function(id, operationListElement)
{
ns = NS(id)
tagList(
wellPanel(
h3(paste0("Operation ", id)),
selectInput(
ns("operationInput"), "Select operation: ",
c("Select & Rename", "Recode", "Joins"), #forget mutate, as, for now
selected = operationListElement[["operationInput"]]
)
)
)
}
modOperationElement = function(input, output, session) {
return(list(operationInput=input$operationInput))
}
## ModOperation ----
modOperationUI = function(id)
{
ns = NS(id)
tagList(
box (
textOutput(ns("testOutput")),
width=12
),
box (
column(
4,
h4("Add Operation"),
actionButton(ns("menuOperation_addOperation_Button"), "Add Table...")
),
column(
4,
h4("Delete Table..."),
selectInput(ns("menuOperation_delOperation_Select"), choices= 1 %>% set_names("Operation One"), label = "Choose Operation: "),
actionButton(ns("menuOperation_delOperation_Button"), "Delete...")
),
width= 12
),
box(
uiOutput(ns("menuOperation_modUI")),
width=12
)
)
}
modOperation = function(input, output, session, i) {
# setup reactive
operation_rvs = reactiveValues() #! I can delete the setup vars!!! - just have to req(operation_rvs[["operation"]]) every observer
# delmodule action ----
observeEvent(input$menuOperation_delOperation_Button, {
operation_rvs[["operation"]][input$menuOperation_delOperation_Select %>% as.integer] <<- NULL
operation_rvs[["ui"]] = modOperationElementUI_List( operation_rvs[["operation"]])
})
# add module action ----
observeEvent(input$menuOperation_addOperation_Button, {
ind = length(operation_rvs[["operation"]])+1
operation_rvs[["operation"]][[ind]] =
list(operationInput="Recode")
operation_rvs[["ui"]] = modOperationElementUI_List( operation_rvs[["operation"]])
})
# update menuOperation Choices
observe({
req(operation_rvs[["operation"]])
updateSelectizeInput(session,
inputId = "menuOperation_delOperation_Select",
choices = 1:length(operation_rvs[["operation"]]) )
})
# recurse UI
output$menuOperation_modUI = renderUI({
req(operation_rvs[["ui"]])
operation_rvs[["ui"]]
})
# recurse server
observe({
req(operation_rvs[["operation"]])
for (i in 1:(length(operation_rvs[["operation"]]) %>% as.integer)) {
operation_rvs[["operation"]][[i]] <<- callModule(modOperationElement, i )
}
})
# test output
output$testOutput = renderPrint(
operation_rvs[["operation"]]
)
}
# UI ----
ui <- dashboardPage(
dashboardHeader(title="Test Conditional Panel in Modules"),
dashboardSidebar(
sidebarMenu(
menuItem("Upload Tables", tabName = "menuUploadTable", icon = icon("file-import"))
)
),
dashboardBody(
tabItems (
## UI: Upload Table ----
tabItem(tabName = "menuUploadTable",
fluidRow(
modOperationUI("operationModule")
)
)
)
)
)
# Server ----
server <- function(input, output, session) {
callModule(modOperation, "operationModule")
}
# Run the application
shinyApp(ui = ui, server = server)