如何在Shiny的observeEvent中运行两个for循环实现一键加载功能
问题原因
核心问题是insertUI的异步执行特性:调用insertUI插入的输入控件不会立刻注册到当前Shiny会话中,插入UI后立刻执行updateSelectInput时,目标控件还未被会话识别,更新指令自然无法生效。
另外你写的load_all事件中第二个lapply存在冗余逻辑,嵌套了两层循环,会重复执行25次更新操作,属于无意义的代码。
解决代码
这里直接采用更高效的方案:在插入UI时直接传入预设的参数值,省去后续更新步骤,从根源避免异步问题,修改后的完整代码如下:
library(shiny) histogramUI <- function(id,var,bins) { tagList( fluidRow(column(4, selectInput(NS(id, "var"), "Variable", choices = names(mtcars),selected=var), numericInput(NS(id, "bins"), "bins", value = bins, min = 1)), column(8, plotOutput(NS(id, "hist")))) ) } histogramServer <- function(id) { moduleServer(id, function(input, output, session) { data <- reactive(mtcars[[input$var]]) output$hist <- renderPlot({ hist(data(), breaks = 10, main = input$var) }, res = 96) }) } ui <- fluidPage( actionButton("load_plots", "Load Plots"), actionButton("load_values", "Load Values"), actionButton("load_all", "Load All"), div(id = "add_here") ) server <- function(input, output, session) { a <- list("hist_1-var" = "hp", "hist_2-var" = "cyl", "hist_3-var" = "am", "hist_4-var" = "disp", "hist_5-var" = "wt") modules <- c("add", "hist_1", "hist_2", "hist_3", "hist_4", "hist_5") observeEvent(input$load_plots, { bins <- 10 if (length(modules)>1) { for (i in 1:(length(modules))) { if (substr(modules[i],1,4)=='hist') { histogramServer(modules[i]) # 直接传入预设的var值 default_var <- a[[paste0(modules[i],"-var")]] insertUI(selector = "#add_here", ui = histogramUI(modules[i], default_var, bins)) } } } }) observeEvent(input$load_values, { for (i in 1:length(a)) { updateSelectInput(session, inputId = names(a[i]), choices = names(mtcars), selected = a[[i]]) } }) observeEvent(input$load_all, { bins <- 10 if (length(modules)>1) { lapply(seq_along(modules), function(i) { if (substr(modules[i],1,4)=='hist') { histogramServer(modules[i]) # 直接传入预设的var值,不需要后续update default_var <- a[[paste0(modules[i],"-var")]] insertUI(selector = "#add_here", ui = histogramUI(modules[i], default_var, bins)) } } ) } # 已经直接传默认值,不需要再执行update操作 }) } shinyApp(ui, server, enableBookmarking = "server")
如果确实需要保留update逻辑(比如参数是动态生成无法提前传入),可以引入shinyjs包的delay函数,先在ui中添加useShinyjs(),再在UI插入逻辑后加delay(100, { update逻辑 })即可,100为延迟毫秒数,可根据实际情况调整。
内容的提问来源于stack exchange,提问作者writer_typer
相关产品推荐
相关产品推荐

