使用insertUI

时间:2020-07-07 11:33:13

标签: r shiny shinymodules

我构建了一个闪亮的应用程序,该应用程序需要基于一些我只能实时知道的参数来动态添加用户界面。我对我的需求进行了简单的重建,并遇到了下面描述的问题

所以在我的示例中,我有一个名为mblock的模块。对于此示例,它仅显示文本。要显示的实际文本是在运行时确定的,因此文本的数量(因此是块)也将在运行时确定

对于特定示例,

我将文本设置为包含要显示的所有文本的固定向量,但实际上,它将被计算为反应对象。代码如下:

library(shiny)

#block module
mblockUI = function(id) {
    ns = NS(id)
    fluidRow(
        textOutput(ns("text"))
    )
}

mblock = function(input,output,session,actual_text) {
    output$text = renderText({actual_text})
}


# Define the main ui 
ui <- fluidPage(
    uiOutput("all_blocks"),
    actionButton("submit","submit")
)

# Define server logic
server <- function(input, output) {
    texts = c("aaaa","bbbb","cccc") #this is a sample vector of texts to be shown in blocks

    output$all_blocks = renderUI({
        for(i in 1:length(texts)) {
            mname = paste0("block",i)  #block name to be created (the name of the module)
            #print(mname)
            insertUI("#submit","beforeBegin",mblockUI(mname))  #adding the ui
            #now adding the server side of each block
            #also passing the text to be shown
            callModule(mblock,mname,texts[i])     
        }
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

问题在于所有块都显示相同的文本(最后一个)。我不明白为什么

有什么想法如何修复代码?我想念什么 (闪亮版本1.4.0)

1 个答案:

答案 0 :(得分:2)

首先,insertUI可以“独立”工作,不需要renderUI。您可以将其放在observe环境中。但是,请注意insertUI的输出,因为它是持久性的,如该函数的文档所述:

与renderUI()不同,使用insertUI()生成的UI是持久的:创建后,它会一直存在,直到被removeUI()删除为止。每个新的insertUI()调用都会创建更多UI对象,除了已经存在的UI对象(彼此独立)。要更新UI的一部分(例如,输入对象),必须使用适当的渲染功能或自定义的反应功能。

我不知道为什么,但是for循环不起作用(如您的示例所示),而lapply起作用(例如,请参见this answer)。

这是您的以下更正示例:

library(shiny)

#block module
mblockUI = function(id) {
  ns = NS(id)
  fluidRow(
    textOutput(ns("text"))
  )
}

mblock = function(input,output,session,actual_text) {
  output$text = renderText({actual_text})
}


# Define the main ui 
ui <- fluidPage(
  actionButton("submit","submit")
)

# Define server logic
server <- function(input, output) {
  texts = c("aaaa","bbbb","cccc") #this is a sample vector of texts to be shown in blocks
  
  observe({
    lapply(1:length(texts), function(i) {
      mname = paste0("block",i)  #block name to be created (the name of the module)
      #print(mname)
      insertUI("#submit","beforeBegin",mblockUI(mname))  #adding the ui
      #now adding the server side of each block
      #also passing the text to be shown
      callModule(mblock,mname,texts[i])     
    })
  })
}

# Run the application 
shinyApp(ui = ui, server = server)