【发布时间】:2022-01-21 15:52:30
【问题描述】:
目标:我创建了一个简单的可重现应用程序,我在其中尝试通过操作按钮添加 UI 组件,以便我可以通过操作按钮生成的 UI 过滤器过滤相同的数据集。我试图在应用过滤器后使用闪亮的模块代码保存数据集,并在下次单击操作按钮时重用过滤后的数据集。换句话说,每次通过单击操作按钮生成一组新的 UI 组件时,我都想重用这个过滤后的数据集(而不是原始的未过滤数据集)。
问题:当用户单击操作按钮时,期望的结果适用于第一个实例,但任何连续单击操作按钮都会导致 错误:承诺已在评估中:递归默认参数引用还是更早的问题? 我试图在闪亮/闪亮的模块中做的事情是不可能的,还是我执行不正确?任何帮助将不胜感激。
library(shiny)
library(dplyr)
add.filter.UI = function(id) {
ns = NS(id)
fluidRow(
column(4, uiOutput(ns("UI_1"))),
column(6, uiOutput(ns("UI_2"))),
column(width = 2,
actionButton(inputId = ns("rm.filter"), label = "Filter", icon = icon("minus"), style = "position: relative; bottom: 0; right:0; top:24px;")),
br(),
column(width = 12, tableOutput(ns("test"))))
}
add.filter.server = function(id, data) {
moduleServer(id, function(input, output, session) {
ns = session$ns
output$UI_1 <- renderUI({
selectInput(inputId = ns("sel.col"),
label = "Select a column",
choices = names(data %>% select_if(is.numeric)),
multiple = F)
})
col.rng = reactive({ data %>% select(one_of(input$sel.col)) })
output$UI_2 = renderUI({
sliderInput(inputId = ns("sel.rng"),
label = "Filter the range",
min = min(col.rng(), na.rm = T),
max = max(col.rng(), na.rm = T),
value = c(min(col.rng(), na.rm = T), max(col.rng(), na.rm = T)),
step = (max(col.rng(), na.rm = T) - min(col.rng(), na.rm = T)) / 100 # of breaks
)
})
data.filtered = reactive({
data %>%
rename(Var = one_of(input$sel.col)) %>%
arrange(Var) %>%
filter(Var >= min(input$sel.rng), Var <= max(input$sel.rng)) %>%
rename(!!input$sel.col := Var)
})
output$test = renderTable({
data.filtered() %>%
head()
})
return( data.filtered )
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
column(width = 2, offset = 10, actionButton(inputId = "add.filter", label = "Filter", icon = icon("plus"), style = "position:relative; left:10px;")),
tags$div(id = 'placeholder')
),
mainPanel(
tableOutput(outputId = "tbl")
)
)
)
server <- function(input, output, session) {
counter = reactiveVal(value = 0)
observeEvent(input$add.filter, {
id <- paste0("#filter_", input$add.filter) # - 1, "-break"
insertUI(selector = "#placeholder",
where = "afterEnd",
ui = tags$div(
add.filter.UI(paste0("filter_", input$add.filter)),
id = id)
)
counter(input$add.filter)
if (counter() == 1) {
df.filtered = add.filter.server(id = paste0("filter_", input$add.filter), data = mtcars)
} else {
df.filtered = add.filter.server(id = paste0("filter_", input$add.filter), data = df.filtered())
}
output$tbl = renderTable({
df.filtered()
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
【问题讨论】:
-
我认为解决方案很复杂,有多个
moduleServer引用并处理相同的tableOutput(outputId = "tbl") generating the errors. Instead, I think that theadd.filter` 操作应该只继续添加 UI,而右侧的数据将被过滤所有 UI 输入只有一个反应式,它将扫描所有输入 UI 以收集过滤条件。 -
@SinhNguyen 谢谢,这很有帮助。如果我不从模块服务器返回它,我将如何扫描所有输入 UI?或者您是说我应该返回 UI 输入而不是模块服务器中的表 (data.filtered)。然后将这些输入存储在应用程序服务器组件的 observeEvent 中的 reactiveValues 对象中,并在每次使用附加过滤器单击 add.filter 操作按钮时更新该对象。