[英]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.