简体   繁体   English

生成动态数量的元素时如何在闪亮渲染中强制评估?

[英]How to force evaluation in shiny render when generating dynamic number of elements?

I generate a dynamic number of valueBox in my shiny, and this number can change depending of the user input.我在 shiny 中生成了一个动态数量的valueBox ,这个数字可以根据用户输入而改变。 I managed to handle this with a renderUI where I put the wanted number of valueBoxOutput , and I have an observe that will feed them with the content using renderValueBox .我设法用一个renderUI来处理这个问题,我在其中放置了所需数量的valueBoxOutput ,并且我有一个observe器,它将使用renderValueBox为它们提供内容。

My problem is: the code in the renderValueBox , for some reason, is actually executed after the observe is finished, so because the renderValueBox is in a loop (to have a dynamic number of them) but the code is executed for all the output after the loop, all my output will get the last value of the loop .我的问题是:由于某种原因, renderValueBox中的代码实际上是在observe完成后执行的,所以因为renderValueBox处于循环中(具有动态数量)但是代码是在之后对所有输出执行的循环,我所有的输出都会得到循环的最后一个值

Here is a min reprex:这是一个最小的代表:

library(shiny)
library(shinydashboard)
library(shinyWidgets)

# Function

compute <- function(id)
{
  print(paste("Compute ", id))
  return(id)
}

# UI

ui = shinyUI(fluidPage(
  
  titlePanel("Compare"),
  useShinydashboard(),
  
  sidebarLayout(
    sidebarPanel(
      numericInput("numitems", label = "Number of items", min = 1, max = 10, value = 2)
    ),
    mainPanel(
      uiOutput("boxes")
    )
  )
))

# Server

server = shinyServer(function(input, output, session) {
  
  data <- reactiveValues(
    ids = list()
  )
  
  output$boxes <- renderUI({
    print("boxes")
    box_list <- list()
    id_list <- list()
    for(id in 1:(input$numitems)) {
      id_box  <- paste0("box_", id)
      print(paste("boxes - ", id_box))
      id_list <- append(id_list, id_box)
      box_list <- append(
        box_list,
        tagList(
          shinydashboard::valueBoxOutput(id_box)
        )
      )
      data$ids <- id_list
    }
    print("boxes end")
    fluidRow(box_list)
  })
  
  observe({
    print("observe")
    for(id_box in data$ids) {
      print(paste("observe - ", id_box))
      output[[id_box]] <- shinydashboard::renderValueBox(valueBox(id_box, compute(id_box), icon = icon("circle-info"), color = "teal"))
    }
    print("end observe")
  })
  
  
})

# Run

shinyApp(ui = ui , server = server)

Here is the result:这是结果:

代表的输出

And the console output:和控制台输出:

控制台的输出

As you can see the compute (and the render in general) is done after the end of the observe function, and both output will use the last id_box that were set (so the last loop, box_2), instead of correctly using box_1 and box_2.如您所见,计算(以及一般的渲染)是在观察函数结束后完成的,并且两个输出都将使用设置的最后一个 id_box(因此最后一个循环,box_2),而不是正确使用 box_1 和 box_2 .

I tried using force , computing valueBox outside the render, using reactive lists, nothing worked, because whatever I do the render is evaluated after the observe so only the last loop values will be used no matter what.我尝试使用force ,在渲染之外计算 valueBox ,使用反应列表,没有任何效果,因为无论我做什么,渲染都是在观察之后评估的,所以无论如何只会使用最后一个循环值。

Do anyone know a way to force execution during the loop?有谁知道在循环中强制执行的方法吗? Or see another way of achieving the same result?或者看到另一种实现相同结果的方法?

Why it's always after spending hald a day on a problem, looking for dozens of posts and forum, don't find anything, finally decide to ask a question... that a few minutes later I finally find an answer.为什么总是在一个问题上花了半天时间,找了几十个帖子和论坛,一无所获,最后决定问一个问题……几分钟后我终于找到了答案。

Anyway, one way to correct this ( found here ) is to encapsulate the render inside the local function, like this:无论如何,纠正此问题的一种方法(在此处找到)是将渲染封装在local函数中,如下所示:

observe({
    print("observe")
    for(id_box in data$ids) {
      print(paste("observe - ", id_box))
      local({
        tmp <- id_box
        output[[tmp]] <- shinydashboard::renderValueBox(valueBox(tmp, compute(tmp), icon = icon("circle-info"), color = "teal"))
      })
    }
    print("end observe")
  })

Now the compute is still called after the end of the observe , but the tmp variable has the correct value:现在compute仍然在observe结束后被调用,但是 tmp 变量有正确的值:

日志控制台

The result is what I wanted:结果是我想要的:

闪亮的结果

For the record, I had already tried to use the local function, but if you don't copy the id_box inside another variable just for the local bloc, it won't work.作为记录,我已经尝试使用local函数,但如果您不将 id_box 复制到另一个变量中,只是为了local集团,它将无法工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM