首页 > 解决方案 > 监听动态创建的闪亮模块

问题描述

我想在我的主应用程序中动态创建模块。这些模块还应该包含一个delete按钮,我想在该按钮上删除我的应用程序中的模块。

以下代码实现了这一点,但前提是我添加了对自身的依赖,这意味着每当我添加新模块handlers时,观察者也会被触发。

从概念上讲,我想使用isolate(handlers()),因为我不想依赖于handlers自身,而只想依赖于handlers.

那么为什么不起作用 isolate(handlers())呢?如何正确依赖模块中的反应器?

library(shiny)
library(magrittr)

example_ui <- function(id) {
  ns <- NS(id)
  fluidRow(id = id,
           h3(id),
           actionButton(ns("delete"), "Delete Me!")
  )
}

example_server <- function(input, output, session) {
  killMe <- reactiveVal(FALSE)

  observeEvent(input$delete, killMe(TRUE))

  list(delete = killMe)
}

ui <- fluidPage(actionButton("add", "Add"), div(id = "container"))

server <- function(input, output, session) {
  handlers <- reactiveVal(list())
  n <- 1

  observeEvent(input$add, {
    id <- paste0("ex_", n)
    n <<- n + 1
    insertUI("#container", "beforeEnd", example_ui(id))
    new_handler <- setNames(list(callModule(example_server, id)),
                            id)
    handlers(c(handlers(), new_handler))
  })

  observe({
    ## would not work: isolate(handlers())
    hdls <- handlers() 
    deregister <- lapply(names(hdls), function(id) {
      handle <- hdls[[id]]
      if (!is.null(handle) && handle$delete()) {
        removeUI(paste0("#", id))
        id
      } else {
        NULL
      }
    }) %>% purrr::flatten_chr()
    hdls[deregister] <- NULL
    handlers(hdls)
  })
}

shinyApp(ui, server)

标签: rshiny

解决方案


所以我想这样做的正确方法是在这样observers的变化上创建handlers

server <- function(input, output, session) {
  handlers  <- reactiveVal(list())
  observers <- list()

  n <- 1

  observeEvent(input$add, {
    id <- paste0("ex_", n)
    n <<- n + 1
    insertUI("#container", "beforeEnd", example_ui(id))
    new_handler <- setNames(list(callModule(example_server, id)),
                            id)
    handlers(c(handlers(), new_handler))
  })

  observe({
    hds <- handlers()
    req(length(hds) > 0)
    new <- setdiff(names(hds),
                   names(observers))

    obs <- setNames(lapply(new, function(n) {
      observeEvent(hds[[n]]$delete(), {
        removeUI(paste0("#", n))
        hds <- handlers()
        hds[n] <- NULL
        handlers(hds)
        observers[n] <<- NULL
      }, ignoreInit = TRUE)
    }), new)
    observers <<- c(observers, obs)
  })
}

推荐阅读