Shiny应用:一个通过renderUI条件渲染的下拉选择框,即使条件不再成立也仍然保留
我正在做一个Shiny应用,里面有多个selectInput控件,其中一个是基于其他选择的条件性显示。一个“演示用的”版本的应用:
# Packages and data: ----
library(shiny)
library(bslib)
samlet_liste <-
list(
"termin1" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3")),
"termin2" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3"))
)
# UI: ----
ui <- fluidPage(
theme = bs_theme(version = 5, bootswatch = "cerulean"),
sidebarLayout(
sidebarPanel(
width = 3,
selectInput("termin", "Termin:", names(samlet_liste)),
selectInput("variant", "Variant:", choices = NULL),
selectInput("model", "Model:", choices = NULL),
uiOutput("conditional_input")
),
mainPanel(
)
)
)
# Server: ----
server <- function(input, output, session){
# Resets variant and model when termin is changed:
observeEvent(input$termin, {
req(input$termin)
updateSelectInput(
session,
"variant",
choices = names(samlet_liste[[input$termin]]),
selected = character(0)
)
updateSelectInput(
session,
"model",
choices = NULL,
selected = character(0)
)
})
# Resets model when variant is changed:
observeEvent(input$variant, {
req(input$variant)
updateSelectInput(
session,
"model",
choices = names(samlet_liste[[input$termin]][[input$variant]]),
selected = character(0)
)
}
)
# Makes conditional selectInput:
output$conditional_input <- renderUI({
req(input$variant)
if (input$variant == c("variant1")) {
selectInput("cond", "Conditional:", choices = c("none", "cond1", "cond2"))
} else {
NULL
}
})
}
shinyApp(ui = ui, server = server)
初次运行应用时,使用renderUI生成的条件性selectInput不会出现,只有在我选择variant > “variant1” 之后才会出现。这符合预期。
不过如果我现在将termin从 “termin1” 更新到 “termin2”,variant的选择将被清空,但条件性selectInput仍然存在。
为什么在variant被清空时,条件性selectInput仍然存在?
解决方案
我相信我已经找到了一个解决办法,但不确定这是一个好办法,还是可能引入其他不可预见的问题。如果有人知道更好的做法(所谓的最佳实践),我也很愿意听取意见。
问题似乎在于,尽管variant已被清空,但renderUI的条件仍然先被检查(在variant被清空之前)。freezeReactiveValue函数解决了这个问题——我并不完全清楚原因。
解决方案:
# Packages and data: ----
library(shiny)
library(bslib)
samlet_liste <-
list(
"termin1" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3")),
"termin2" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3"))
)
# UI: ----
ui <- fluidPage(
theme = bs_theme(version = 5, bootswatch = "cerulean"),
sidebarLayout(
sidebarPanel(
width = 3,
selectInput("termin", "Termin:", choices = names(samlet_liste)),
selectInput("variant", "Variant:", choices = NULL),
selectInput("model", "Model:", choices = NULL),
uiOutput("conditional_input")
),
mainPanel()
)
)
# Server: ----
server <- function(input, output, session){
# Resets variant and model when termin is changed:
observeEvent(input$termin, {
req(input$termin)
# Freezing these inputs so downstream elements don't read stale values
freezeReactiveValue(input, "variant")
freezeReactiveValue(input, "model")
updateSelectInput(
session,
"variant",
choices = names(samlet_liste[[input$termin]]),
selected = character(0)
)
updateSelectInput(
session,
"model",
choices = NULL,
selected = character(0)
)
})
# Updates model when variant is changed:
observeEvent(input$variant, {
req(input$variant)
freezeReactiveValue(input, "model")
updateSelectInput(
session,
"model",
choices = names(samlet_liste[[input$termin]][[input$variant]]),
selected = character(0)
)
})
# Makes conditional selectInput:
output$conditional_input <- renderUI({
req(input$variant)
if (input$variant == "variant1") {
selectInput("cond", "Conditional:", choices = c("none", "cond1", "cond2"))
} else {
NULL
}
})
}
shinyApp(ui = ui, server = server)
备选方案
la i laps在原始问题的评论中提出了一个更好的解决方案。
他的解决方案(不使用freezeReactiveValue):
# Packages and data: ----
library(shiny)
library(bslib)
samlet_liste <-
list(
"termin1" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3")),
"termin2" = list("variant1" = list("model1" = "1", "model2" = "2", "model3" = "3"),
"variant2" = list("model1" = "1", "model2" = "2", "model3" = "3"))
)
# UI: ----
ui <- fluidPage(
theme = bs_theme(version = 5, bootswatch = "cerulean"),
sidebarLayout(
sidebarPanel(
width = 3,
selectInput("termin", "Termin:", names(samlet_liste)),
selectInput("variant", "Variant:", choices = NULL),
selectInput("model", "Model:", choices = NULL),
uiOutput("conditional_input")
),
mainPanel(
)
)
)
# Server: ----
server <- function(input, output, session){
# Resets variant and model when termin is changed:
observeEvent(input$termin, {
req(input$termin)
updateSelectInput(
session,
"variant",
choices = c(" ", names(samlet_liste[[input$termin]])),
selected = " "
)
updateSelectInput(
session,
"model",
choices = c(" "),
selected = " "
)
})
# Resets model when variant is changed:
observeEvent(input$variant, {
req(input$variant)
updateSelectInput(
session,
"model",
choices = c(" ", names(samlet_liste[[input$termin]][[input$variant]])),
selected = " "
)
}
)
# Makes conditional selectInput:
output$conditional_input <- renderUI({
req(input$variant)
if (input$variant == c("variant1")) {
selectInput("cond", "Conditional:", choices = c("none", "cond1", "cond2"))
} else {
NULL
}
})
}
shinyApp(ui = ui, server = server)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。